我想在我们的开源库中使用 C++11 关键字 thread_local,它可以在静态变量的上下文中动态或静态链接到许多平台(Windows、Linux、Mac OS...) 。这个变量是一个类类型,基本上只是封装一个 std::stringstream 变量并初始化它以满足我们的 stringstream 格式要求。出于性能原因,我们希望使其静态可用(有关更多详细信息,请参阅我之前的问题),如果这是每个线程完成的,那也没关系。
全局变量应该在静态模板类方法中使用,并且必须在标头中实现。但这意味着,如果我理解正确的话,库的用户可能会在其可执行文件的代码中包含此标头,这会将模板化方法编译到可执行文件中。然后,这些方法将从可执行文件的线程内访问提到的全局变量。我需要如何声明/定义静态变量才能使其工作,即我是否需要导出变量或类类型,或者声明它“static thread_local X”就足够了吗?这是我目前的声明:
// SharedStringstream.h
#include <sstream>
// Export stands for _declspec(dllimport) or (dllexport) respectively
class EXPORT SharedStringstream
{
public:
SharedStringstream();
static thread_local SharedStringstream s_sharedStreamInstance;
std::stringstream d_sharedStream;
};
和定义:
// SharedStringstream.cpp
#include "SharedStringStream.h"
SharedStringstream SharedStringstream::s_sharedStreamInstance();
SharedStringstream::SharedStringstream()
{
d_sharedStream.imbue(std::locale("C"));
d_sharedStream << std::skipws;
d_sharedStream >> std::skipws;
}
如果没有导出,我会收到链接器错误,使用它,我会在 Visual Studio 2015 中收到以下错误:
错误C2492'public:static SharedStringstream SharedStringstream :: s_sharedStreamInstance':具有线程存储持续时间的数据可能没有dll接口
更多信息在 here 给出,基本上表明
thread_local
变量可能无法导出。为此,我必须将其从类中移到我的命名空间中,这是唯一的方法吗?
此外: 关于 “Thread Local Storage” 的 MSDN 页面对
thread_local
和 DLL 做了如下说明:
使用线程属性可能会干扰 DLL 导入的延迟加载。
我们确实在内部对库中包含的某些插件使用了 DLL 的延迟加载,但不会对变量进行任何调用。不过,我认为用户可以延迟加载该库,尽管我们并不正式支持这一点。假设我们不支持库的延迟加载,并且不从内部任何延迟加载的 dll 调用变量,我们是否能够确保这在任何情况下都不会成为问题?
我的问题中还有哪些问题没有考虑到吗?
您可以隐藏
thread_local
变量而不导出它,并且具有静态 getter。
正如链接文章所暗示的那样,主要限制来自于无法获取已运行线程的
DLL_THREAD_ATTACH
消息。
为了避免这两个限制:
thread_local
变量隐藏在实现中,未导出像这样:
// SharedStringstream.h
#include <sstream>
// Export stands for _declspec(dllimport) or (dllexport) respectively
class EXPORT SharedStringstream
{
public:
SharedStringstream();
static SharedStringstream& GetSharedStreamInstance();
std::stringstream d_sharedStream;
}
// SharedStringstream.cpp
#include "SharedStringStream.h"
static thread_local std::unique_ptr<SharedStringstream> s_sharedStreamInstance;
/* static */ SharedStringstream& SharedStringstream::s_sharedStreamInstance()
{
std::unique_ptr<SharedStringstream>& inst = s_sharedStreamInstance;
if (inst == nullptr)
{
inst = std::make_unique<SharedStringstream>();
}
return *inst;
}
当 dll 加载时,它会加载自己的内存模型。因此,任何静态代码都不会在不同进程之间共享。