2013年5月27日星期一

一个坑:crontab中使用sudo

最近,一个进程总是无法被crontab拉起,加了日志观察后,发现这一句错误信息:
sudo: sorry, you must have a tty to run sudo

google一下发现这篇帖子:http://gcoder.blogbus.com/logs/49929050.html

解决办法为:
vi /etc/sudoers
#注释掉 Defaults    requiretty

搞定!

2013年4月11日星期四

为什么64位下用python调用C库发生了崩溃

在64位下,把一些库封装成C函数,然后编译成so文件供python调用,结果发生了崩溃。
今天试验后发现:如果C函数返回void*等类型,把返回值赋值到python变量后被截断,只剩下低32位的值。
因此,如果C函数中的指针在0xffffffff以上的地址的时候,返回到python中就会被截断。如果再继续使用这个被截断后的地址值,就会发生崩溃。

下面是模拟崩溃的代码:
//C
void* create_object()
{
    return new int(0);
}

void free_object(void* obj)
{
    delete (int*)obj;
}

#python中这样调用
so = cdll.LoadLibrary('xxxx.so')
obj = so.create_object()  #这里被截断
so.free_object(obj)       #这里发生崩溃

=====================================================
解决办法也比较简单,不要通过返回值传递指针,而通过指针参数返回:

void create_object(uint64_t* out)
{
    *out = (uint64_t)new int(0);
}

void free_object(void* obj)
{
    delete (int*)obj;
}



#python中这样调用
so = cdll.LoadLibrary('xxxx.so')
obj = ctypes.c_ulonglong(0)
so.create_object(ctypes.byref(obj))
obj = ctypes.c_void_p(obj.value)
so.free_object(obj)


这里要注意:发现python中的对象的地址都在0xffffffff之内,所以使用byref没发现问题。
byref是否会截断指针,这个还没试验出来。

2013年4月1日星期一

linux64下的一个链接问题: crtbeginT.o

尝试链接一个动态库,结果crtbeginT.o这个系统库出现错误:


g++ -o ttc_api_c.o -c ttc_api_c.cpp -g -Wall -Werror -O2 -fPIC
g++ -o ttc_api_c.so -shared ttc_api_c.o libttc.pic_64.a -static
/usr/bin/ld: /usr/lib/gcc/x86_64-redhat-linux/4.4.6/crtbeginT.o: relocation R_X86_64_32 against `__DTOR_END__' can not be used when making a shared object; recompile with -fPIC
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/crtbeginT.o: could not read symbols: Bad value
collect2: ld returned 1 exit status

百思不得其姐,还好搜索到这篇帖子:
https://bugs.launchpad.net/ubuntu/+source/gcc-4.4/+bug/640734

采用文中的办法,酱紫解决了:

cd /usr/lib/gcc/x86_64-redhat-linux/4.4.6
cp crtbeginT.o crtbeginT.orig.o
cp crtbeginS.o crtbeginT.o



2012年12月30日星期日

2012年12月27日星期四

转:各种操作的延迟时间

下图来自此页面:http://blog.hesey.net/2012/06/evolution-of-large-website-architecture.html


另有一张同事贴的页面:http://www.eecs.berkeley.edu/~rcs/research/interactive_latency.html
比较有趣,每年的变化都能看见,不知道是如何预测出来的。

protocol buffers and thrift:当心类型暴涨

最近在阅读另一个部门交接的代码。
尝试增加一个小小的新功能,然后编译、链接……这个过程相当痛苦。
这个部门在数据传输协议上,采用了类似于protocol buffers或thrift类似的技术:用中间语言定义类型,然后用工具编译成C++代码。

这样做无可厚非。但我在阅读代码和编译链接的时候,非常痛苦:
1、 类型实在太多了,类型套类型,分散在很多个不同的目录中;
2、编译不通过,必须把所有引用到的类型的头文件都include进去;链接也不通过,必须把类型的encode/decode库链接进去。

因此,使用protocol buffers and thrift类似的技术初看很好,随着业务的发展,类型越来越多,代码就变得越来越臃肿,越来越难以维护。

我建议,这样去避免类型暴涨:
1. 采用自动编译,把中间的定义文件放在某个目录下,自动生成各种语言需要的代码;
2. 所有的类型放在一起,甚至可以把所有的类型包含在一个all_types.h中;后续的代码要引用类型,包含这一个头文件即可。怕影响编译速度?可以用预编译头文件解决;
3. 所有的类型的encode/decode代码,全部编译后,打包到一个大的all_types.a中,到时候链接一个库即可;
4. 定期清理,不要的类型丢弃。

2012年12月20日星期四

试验:多线程竞争写

下面一段代码将试验不同条件下多线程竞争对变量进行累加的效果:

#include <stdio.h>
#include <pthread.h>

#define MAX_NUM 5000000

int num = 0;

void* thread_func(void* param)
{
for (int i=0; i<MAX_NUM; ++i)
{
++num;
}
return NULL;
}

int main()
{
pthread_t t1, t2;
pthread_create(&t1, NULL, thread_func, NULL);
pthread_create(&t2, NULL, thread_func, NULL);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
printf("%d\n", num);
return 1;
}

假设没有竞争,则num最终输出的结果应该是10000000

试验一:执行上面的代码输出5315953
试验二:将蓝色的这行的定义修改为:volatile int num = 0;
        执行后输出5431651。
        虽然没有得到正确的结果,但从数值上看出,volatile对数据同步还是有一些效果的。
试验三:在红色的行前增加一行代码:__sync_synchronize();
        执行后输出7443185
        试验说明,内存屏障能够进一步加快多核间的内存数据同步。
试验四:将红色的这行修改为__sync_add_and_fetch(&num, 1);
        执行后得到了正确结果10000000
        由此说明,多核条件下并发累加,只有原子操作才能得到正确的结果。volatile关键字和内存屏障都不能解决。
==============================================
进一步思考:如下是CPU的结构图
线程在操作num这个数的时候,都会把num载入自己的 L1 cache line
当CPU0上的线程1改写了num的值,L1 cache line为标示为脏。然后,CPU0上的cache line会同步到CPU 1上的cache line,然后CPU1读取数据的时候,就会是最新的数据。

如果按照这种数据同步原理,则试验一应该得到正确的结果。但为什么结果又不正确呢?

CPU, L1 CACHE, 内存,这三者之间的数据同步机制究竟是如何进行的?希望有大虾予以指教。