线程本地存储开销 [英] thread-local storage overhead

查看:74
本文介绍了线程本地存储开销的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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 */
}

或者,通过使用gcc __thread说明符,更加简单:

or, by using gcc __thread specifier, more simplier:


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

最后一个优点是我不需要更改另一个调用foo()的代码.

Advantages of the last is that I don't need to change another code which call foo().

我的问题是,线程本地存储的开销是多少? TLS是否存在一些不明显的问题?

My questions is, how much overhead of thread-local storage is? Is there some not obvious issues with TLS?

如果我要通过单独的指针修改TLS`ed变量,是否会有一些开销,例如:

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 */
}

谢谢.

推荐答案

然后,我想使用此功能 在多线程代码中,所以我可以更改 这样编写代码:

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

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

这肯定是 无效的,因为您将只修改i的副本.如果要保留更改,则需要传递int*int&.

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.

使用TLS肯定不会在实现相同功能的任何自定义方法上引起任何重大的开销(无论是空间还是时间).实际上,编译器通过在包含线程局部变量的全局数据结构中动态分配存储插槽"来实现TLS.

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.

在运行时访问线程局部变量时,还有一个间接级别:首先,运行时必须访问当前线程的相应线程局部变量表,然后从表中获取值. .通过使用数组索引(这是O(1)操作)来完成此提取.

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).

如果您打算这样做:

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

则无需使用指针访问i.可以将i视为一个全局变量,该变量对于每个正在运行的线程都具有不同的值.您无需通过指针访问普通的全局变量即可使更改生效,因此也无需使用带有线程局部变量的指针.

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.

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

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.

这篇关于线程本地存储开销的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆