线程本地存储开销

发布于 2024-10-27 05:16:29 字数 561 浏览 6 评论 0原文

假设有一些不可重入的函数使用全局变量:


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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

壹場煙雨 2024-11-03 05:16:29

然后,我想使用这个功能
在多线程代码中,所以我可以改变
代码如下:

void foo(int i){
    /* modify i */
}

这肯定不会起作用,因为您只会修改 i 的副本。如果您希望保留更改,则需要传递 int*int&

与您为实现相同功能而采用的任何自定义方法相比,使用 TLS 当然不会造成任何重大开销(无论是空间还是时间)。实际上,编译器通过在保存线程局部变量的全局数据结构中动态分配存储“槽”来实现 TLS。

当您在运行时访问线程局部变量时,存在额外的间接级别:首先,运行时必须访问当前线程的适当线程局部变量表,然后从表中获取值。此获取是使用数组索引完成的(这是一个 O(1) 操作)。

如果您打算这样做:

__thread int i;
void foo(void){
    int *p = &i;
    /* modify i using p pointer */
}

那么就不需要使用指针访问i。将 i 视为一个全局变量,对于每个正在运行的线程都有不同的值。您不需要通过指针访问普通的全局变量来保持更改,因此也不需要将指针与线程局部变量一起使用。

最后,线程本地存储并不是真正意味着每个线程存储大量变量(TLS 表的大小存在编译器相关的限制),但您可以轻松解决此问题:将许多变量放入 struct 并创建一个指向线程本地struct 的指针。

And then, I want to use this function
in multithreaded code, so I can change
code this way:

void foo(int i){
    /* modify i */
}

This will certainly not work, as you will only be modifying a copy of i. You 'd need to pass an int* or int& 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:

__thread int i;
void foo(void){
    int *p = &i;
    /* modify i using p pointer */
}

then there is no need to access i using a pointer. Think of i 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 the struct thread-local.

过度放纵 2024-11-03 05:16:29

我认为 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)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文