线程本地存储开销
假设有一些不可重入的函数使用全局变量:
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 */
}
谢谢。
Assume there is some not-reentrant function that uses global variables:
int i;
void foo(void){
/* modify i */
}
And then, I want to use this function in multithreaded code, so I can change code this way:
void foo(int i){
/* modify i */
}
or, by using gcc __thread specifier, more simplier:
__thread int i;
void foo(void){
/* modify i */
}
Advantages of the last is that I don't need to change another code which call foo().
My questions is, how much overhead of thread-local storage is? Is there some not obvious issues with TLS?
Is there some overhead if I will modify TLS`ed variable via separate pointer, like this:
__thread int i;
void foo(void){
int *p = &i;
/* modify i using p pointer */
}
Thanks.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这肯定不会起作用,因为您只会修改
i
的副本。如果您希望保留更改,则需要传递int*
或int&
。与您为实现相同功能而采用的任何自定义方法相比,使用 TLS 当然不会造成任何重大开销(无论是空间还是时间)。实际上,编译器通过在保存线程局部变量的全局数据结构中动态分配存储“槽”来实现 TLS。
当您在运行时访问线程局部变量时,存在额外的间接级别:首先,运行时必须访问当前线程的适当线程局部变量表,然后从表中获取值。此获取是使用数组索引完成的(这是一个 O(1) 操作)。
如果您打算这样做:
那么就不需要使用指针访问
i
。将i
视为一个全局变量,对于每个正在运行的线程都有不同的值。您不需要通过指针访问普通的全局变量来保持更改,因此也不需要将指针与线程局部变量一起使用。最后,线程本地存储并不是真正意味着每个线程存储大量变量(TLS 表的大小存在编译器相关的限制),但您可以轻松解决此问题:将许多变量放入
struct
并创建一个指向线程本地struct
的指针。This will certainly not work, as you will only be modifying a copy of
i
. You 'd need to pass anint*
orint&
instead if you want the changes to stick.Using TLS will certainly not cause any significant overhead (either in space or time) over any custom approach you might follow to implement the same functionality. Compilers in practice implement TLS by dynamically allocating a storage "slot" in a global data structure that holds your thread-local variable.
When you access a thread-local variable at runtime, there is an extra level of indirection: first the runtime has to access the appropriate thread-local variable table for the current thread, and then to fetch the value out of the table. This fetching is done using an index into the array (which is an O(1) operation).
If you intend to do this:
then there is no need to access
i
using a pointer. Think ofi
as a global variable that has a different value for each running thread. You wouldn't need to access a normal global through a pointer to make changes stick, so there's also no need to use a pointer with a thread-local variable.Finally, thread-local storage is not really meant to store large numbers of variables per thread (there are compiler-dependent limits on the size of the TLS table) but this is something you can easily work around: put many variables into a
struct
and make a pointer to thestruct
thread-local.我认为 TLS 的唯一问题是它的大小可能有限。这取决于系统,因此您可能会面临移植或扩展问题(顺便说一句,TLS 在某些系统上可能根本不可用)
The only problem I see with TLS is its possible limited size. It depends on the system, so you can face porting or scaling problems (BTW, TLS may be not available at all on some systems)