同步操作将从 百度开源/incubator-brpc 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
本页说明bthread下使用pthread-local可能会导致的问题。bthread-local的使用方法见这里。
调用阻塞的bthread函数后,所在的pthread很可能改变,这使pthread_getspecific,gcc __thread和c++11 thread_local变量,pthread_self()等的值变化了,如下代码的行为是不可预计的:
thread_local SomeObject obj;
...
SomeObject* p = &obj;
p->bar();
bthread_usleep(1000);
p->bar();
bthread_usleep之后,该bthread很可能身处不同的pthread,这时p指向了之前pthread的thread_local变量,继续访问p的结果无法预计。这种使用模式往往发生在用户使用线程级变量传递业务变量的情况。为了防止这种情况,应该谨记:
gcc4会优化标记为__attribute__((const))的函数,这个标记大致指只要参数不变,输出就不会变。所以当一个函数中以相同参数出现多次时,gcc4会合并为一次。比如在我们的系统中errno是内容为*__errno_location()的宏,这个函数的签名是:
/* Function to get address of global `errno' variable. */
extern int *__errno_location (void) __THROW __attribute__ ((__const__));
由于此函数被标记为__const__
,且没有参数,当你在一个函数中调用多次errno时,可能只有第一次才调用__errno_location(),而之后只是访问其返回的int*
。在pthread中这没有问题,因为返回的int*
是thread-local的,一个给定的pthread中是不会变化的。但是在bthread中,这是不成立的,因为一个bthread很可能在调用一些函数后跑到另一个pthread去,如果gcc4做了类似的优化,即一个函数内所有的errno都替换为第一次调用返回的int*,这中间bthread又切换了pthread,那么可能会访问之前pthread的errno,从而造成未定义行为。
比如下文是一种errno的使用场景:
Use errno ... (original pthread)
bthread functions that may switch to another pthread.
Use errno ... (another pthread)
我们期望看到的行为:
Use *__errno_location() ... - the thread-local errno of original pthread
bthread may switch another pthread ...
Use *__errno_location() ... - the thread-local errno of another pthread
使用gcc4时的实际行为:
int* p= __errno_location();
Use *p ... - the thread-local errno of original pthread
bthread context switches ...
Use *p ... - still the errno of original pthread, undefined behavior!!
严格地说这个问题不是gcc4导致的,而是glibc给__errno_location的签名不够准确,一个返回thread-local指针的函数依赖于段寄存器(TLS的一般实现方式),这怎么能算const呢?由于我们还未找到覆盖__errno_location的方法,所以这个问题目前实际的解决方法是:
务必在直接或间接使用bthread的项目的gcc编译选项中添加-D__const__=
,即把__const__
定义为空,避免gcc4做相关优化。
把__const__
定义为空对程序其他部分的影响几乎为0。另外如果你没有直接使用errno(即你的项目中没有出现errno),或使用的是gcc
3.4,即使没有定义-D__const__=
,程序的正确性也不会受影响,但为了防止未来可能的问题,我们强烈建议加上。
需要说明的是,和errno类似,pthread_self也有类似的问题,不过一般pthread_self除了打日志没有其他用途,影响面较小,在-D__const__=
后pthread_self也会正常。
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。