假设有一些不可重入函数使用全局变量:
int i;
void foo(void){
/* modify i */
}
然后,我想在多线程代码中使用这个函数,所以我可以这样更改代码:
void foo(int i){
/* modify i */
}
或者,通过使用 gcc __thread 说明符,更简单:
__thread int i;
void foo(void){
/* modify i */
}
最后一个的优点是我不需要更改另一个调用 foo() 的代码。
我的问题是,线程本地存储的开销是多少? TLS 是否存在一些不明显的问题?
如果我通过单独的指针修改 TLS`ed 变量,是否会产生一些开销,如下所示:
__thread int i;
void foo(void){
int *p = &i;
/* modify i using p pointer */
}
Thanks.
然后我想使用这个功能
在多线程代码中,所以我可以改变
代码如下:
void foo(int i){
/* modify i */
}
这肯定会not工作,因为您只会修改i
。你需要通过int*
or int&
相反,如果您希望更改保持不变。
与您为实现相同功能而采用的任何自定义方法相比,使用 TLS 当然不会造成任何重大开销(无论是空间还是时间)。实际上,编译器通过在保存线程局部变量的全局数据结构中动态分配存储“槽”来实现 TLS。
当您在运行时访问线程局部变量时,存在额外的间接级别:首先,运行时必须访问当前线程的适当线程局部变量表,然后从表中获取值。此获取是使用数组索引完成的(这是一个 O(1) 操作)。
如果您打算这样做:
__thread int i;
void foo(void){
int *p = &i;
/* modify i using p pointer */
}
那么就不需要访问i
使用指针。考虑到i
作为一个全局变量,对于每个正在运行的线程都有不同的值。您不需要通过指针访问普通的全局变量来保持更改,因此也不需要将指针与线程局部变量一起使用。
最后,线程本地存储并不是真正意味着每个线程存储大量变量(TLS 表的大小存在编译器相关的限制),但这是您可以轻松解决的问题:将许多变量放入一个struct
并创建一个指向struct
线程局部的。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)