我对thread_localC++ 11中的描述感到困惑.我的理解是,每个线程在函数中都有唯一的局部变量副本.所有线程都可以访问全局/静态变量(可能使用锁进行同步访问).和thread_local变量的所有线程都是可见的,但只能由他们为其定义线程修改?这是对的吗?
这两个代码段之间是否存在差异:
void f() {
thread_local vector<int> V;
V.clear();
... // use V as a temporary variable
}
Run Code Online (Sandbox Code Playgroud)
和
void f() {
static thread_local vector<int> V;
V.clear();
... // use V as a temporary variable
}
Run Code Online (Sandbox Code Playgroud)
Backstory:最初我有一个STATIC向量V(用于保存一些中间值,每次进入函数时都会被清除)和一个单线程程序.我想把程序变成多线程程序,所以我不得不摆脱这个静态修饰符.我的想法是将每个静态转换为thread_local并且不担心其他任何事情?这可能会适得其反吗?
如何在Python中使用线程本地存储?
我的函数中有一个变量是静态的,但我希望它在每个线程的基础上是静态的.
如何为我的C++类分配内存,以便每个线程都有自己的类实例副本?
AnotherClass::threadSpecificAction()
{
// How to allocate this with thread local storage?
static MyClass *instance = new MyClass();
instance->doSomething();
}
Run Code Online (Sandbox Code Playgroud)
这是在Linux上.我没有使用C++ 0x,这是gcc v3.4.6.
我正在为D编程语言开发一个自定义标记释放样式的内存分配器,它通过从线程局部区域分配来工作.似乎线程本地存储瓶颈导致从这些区域分配内存的巨大(~50%)减速与相同的单线程版本的代码相比,即使在设计我的代码以使每个分配只有一个TLS查找/释放.这是基于在循环中多次分配/释放内存,我试图弄清楚它是否是我的基准测试方法的工件.我的理解是线程本地存储基本上只需要通过额外的间接层访问某些东西,类似于通过指针访问变量.这是不正确的?线程本地存储通常有多少开销?
注意:虽然我提到D,但我也对D不具体的一般答案感兴趣,因为如果它比最佳实现慢,D的线程局部存储的实现可能会有所改进.
__thread Foo foo;
Run Code Online (Sandbox Code Playgroud)
"foo"如何实际解决?编译器是否以函数调用静默替换"foo"的每个实例?"foo"存储在相对于堆栈底部的某处,并且编译器将其存储为"嘿,对于每个线程,将此空间放在堆栈底部附近,并将foo存储为'堆栈底部的偏移x' "?
更新于2014年11月18日 - 在浏览log4net源存储库时,我发现LogicalThreadContext的实现在2011年11月被修改为使用CallContext.LogicalSetData存储其属性(并使用LogicalGetData获取它们).这很重要,因为这意味着LogicalThreadContext现在应该可以正常工作.存储在LogicalThreadContext中的任何数据都应"流向"任何子线程或任务.这与ThreadContext(以及LogicalThreadContext的旧实现)相比较,其中存储在上下文中的数据将保持在当前线程的本地,而不是流向子线程/任务.
如果您有兴趣,可以参考以下内容:
希望有人发现这个老问题会发现这些信息很有用.
log4net提供了两个不同的"线程上下文"对象:ThreadContext和LogicalThreadContext,每个对象 都有一个属性包.ThreadContext有一个ThreadContextProperties包,而LogicalThreadContext有一个LogicalThreadContextProperties包.
ThreadContext可能更常被称为"MDC".LogicalContext可能更常被称为"LDC".我会在这篇文章的其余部分使用短名称.
MDC.Properties使用System.Threading.Thread.SetData实现,而LDC.Properties使用System.Runtime.Remoting.Messaging.CallContext.SetData实现.
为了进行比较,NLog仅公开"MDC"(现在称为MappedDiagnosticContext)来存储线程本地属性.NLog的实现使用System.Threading.Thread.SetData,因此它的实现与log4net相同.
在log4net和NLog中,"MDC"属性存储在字典中,该字典本身存储在线程本地存储中.
在这样的情况下,将字典存储在用[ThreadStatic]装饰的类成员变量中是否相同?
[ThreadStatic]
private static IDictionary<string, string> threadProperties;
Run Code Online (Sandbox Code Playgroud)
什么是使用.NET 4.0的新ThreadLocal类的等效(或类似)声明?
最终,LDC和MDC之间真正的,实际的差异是什么?即使在阅读了上面链接的MSDN主题之后,我也不清楚.你什么时候真的使用一个而不是另一个?似乎我在log4net和上下文中看到的绝大多数引用/示例都是针对GDC(全局 - 我理解),NDC(嵌套 - 我也理解)和MDC.我在google搜索时可以找到LDC(或LogicalThreadContext)的大多数引用都与登录到log4net源代码库有关,而不是真实世界的用法.最不发达国家几乎从未提出问题或例子.
我确实找到了这个链接,提供了一些关于与log4net开发人员之一Nicko Cadell的差异的非常好的信息,但我仍然不清楚.
一个更大的问题,与log4net没有直接关系的是Thread.SetData和CallContext.SetData之间的实际区别是什么?
根据CallContext MSDN文章,CallContext数据可以传播到另一个AppDomain.要传播,存储在CallContext中的数据项必须公开ILogicalThreadAffinative接口.所以,这似乎是Thread.SetData和CallContext之间的一个区别.
根据Nicko Cadell链接,log4net不实现ILogicalThreadAffinative,因此不会传播LDC属性.
也许这里有足够的东西我应该能够回答我自己的问题,也许不是.我还在努力理解.
如果你使用log4net,你们每个人都使用MDC,LDC吗?如果你使用MDC,是因为大多数"真实世界"的例子似乎都在使用它吗?如果你使用LDC,你有特定的理由使用它吗?如果你同时使用它们,你如何选择何时使用哪个?
请注意,我已经看到一些关于MDC(也许是LDC)的文章可能因为线程切换而无法在ASP.net应用程序中正常工作.我对这个问题不是特别感兴趣,因为我不在ASP.net工作.
实际上,我在SO上发现了一些可能有助于讨论的有用帖子:
提前致谢!
#include <cstdlib>
#include <thread>
#include <chrono>
#include <iostream>
using namespace std;
using namespace std::literals;
struct A
{
int n_ = 0;
A(int n) : n_(n) { cout << "A:" << n_ << endl; }
~A() { cout << "~A:" << n_ << endl; }
};
A a1(1);
int main()
{
std::thread([]()
{
static A a2(2);
thread_local A a3(3);
std::this_thread::sleep_for(24h);
}).detach();
static A a4(4);
thread_local A a5(5);
std::this_thread::sleep_for(1s);
std::exit(0);
}
Run Code Online (Sandbox Code Playgroud)
我的编译器是clang 5.0用-std=c++1z.
输出如下:
Run Code Online (Sandbox Code Playgroud)A:1 A:2 A:4 A:5 …
如何__thread实现gcc?它只是一个包装pthread_getspecific和pthread_setspecific?
我的程序使用posix API进行TLS,现在我看到30%的程序运行时都用在了上面,我感到很失望pthread_getspecific.我在每个需要资源的函数调用的条目上调用它.pthread_getspecific在内联优化之后,编译器似乎没有优化.因此,在内联函数之后,代码基本上一次又一次地搜索正确的TLS指针以获得返回的相同指针.
__thread在这种情况下会帮助我吗?我知道thread_localC11中有,但我所拥有的gcc还不支持它.(但现在我看到我的gcc确实支持_Thread_local不是宏.)
我知道我可以简单地测试一下然后看看.但是我现在必须去别的地方了,在我尝试重大改写之前,我想更好地了解一个功能.
如何从另一个线程读取/写入线程局部变量?也就是说,在线程AI中想要访问线程B的线程本地存储区域中的变量.我知道另一个线程的ID.
该变量__thread在GCC中声明.目标平台是Linux,但独立性可能不错(但GCC具体可行).
缺少线程启动挂钩,我无法在每个线程的开头简单地跟踪此值.需要以这种方式跟踪所有线程(不仅仅是特别启动的线程).
像boost boost_local_storage或使用pthread键的更高级别的包装器不是一个选项.我要求使用真正的__thread局部变量.
第一个答案是错误的:人们不能将全局变量用于我想做的事情.每个线程必须有自己的变量副本.此外,__thread出于性能原因,这些变量必须是变量(同样有效的解决方案也可以,但我不知道).我也不控制线程入口点,因此这些线程不可能注册任何类型的结构.
线程本地不是私有的:另一个关于线程局部变量的误解.这些线程绝不是某种私有变量.它们是全局可寻址的内存,其限制是它们的生命周期与线程相关联.任何线程中的任何函数,如果给出指向这些变量的指针,都可以修改它们.上面的问题主要是关于如何获得指针地址.
c++ ×5
c++11 ×3
gcc ×3
linux ×3
.net ×1
c ×1
d ×1
destructor ×1
log4net ×1
logging ×1
new-operator ×1
nlog ×1
performance ×1
python ×1
thread-local ×1