全局变量构造函数/析构函数是否需要线程保护
Do global variable constructors/destructors need thread protection?
如果我有一个类的唯一目的是拥有全局static
实例(以确保其构造函数中的代码在main
之前运行),并且它使用了一个类static
变量,那么对该变量的访问是否需要通过互斥来保护?
一个例子会有所帮助:
class WinSock
{
public:
WinSock()
{
if(!(inst++))
//winsock init
}
~WinSock()
{
if(!--inst)
//winsock deactivate
}
private:
static int inst = 0;
}
static WinSock unusedWinSockVar;
这一切都在一个头中,任何使用winsock的文件都会包含这个头。对inst
的访问是否需要保护,或者该代码是否不可能从多个线程运行,因为线程只会在main
运行一次后创建,并在main
返回之前销毁?
首先,我不认为private: static int inst = 0;
是一个有效的构造,我的编译器大声抱怨-如果为了简单起见,您在项目中的某个.cpp文件中忽略了类似int WinSock::inst = 0
的内容,那么没关系。如果不是,并且您的项目进行了编译,那么很有可能所有翻译单元都会使用不同的变量,从而导致错误的行为。
其次,如果任何静态对象构造函数创建了一个新线程,那么您需要确保代码线程的安全。来自C++标准第3.6.2页:
如果程序启动线程(30.3)变量相对于在不同的翻译单位中定义的变量。否则变量的初始化相对于初始化在不同翻译中定义的变量单元
不确定排序意味着初始化不会有任何特定的顺序,但不会重叠,因此不需要任何额外的保护措施。没有排序意味着不同编译unis中的构造函数可能会重叠,因此需要线程安全性。
第三,你需要这样做吗?你有其他在构造函数中使用winsock的静态对象吗?我真的想不出有什么其他理由这样做。
考虑到您所描述的特定场景,这在不添加同步的情况下是可以的。
您担心的是Winsock在main
运行之前(之后)被初始化(和取消初始化),这是肯定的。代码也保证只能从一个线程调用一次。这(事实上只有一个线程)使得同步变得毫无用处。
假设其他静态全局对象使用Winsock(无论它们是否生成线程),这当然是不安全的,但使用互斥也不会更安全。初始化发生在main
之前的实现定义的时间点
因此,任何静态全局对象都不能使用此构造以安全、定义良好的方式使用Winsock,因为无论哪种方式,您都不知道初始化是否首先发生。同步它不会改变任何细节。
注意:inst
在类声明中的初始化是不允许的。
- 从不同线程使用int64的不同字节安全吗
- 删除一个线程上有数百万个字符串的大型哈希映射会影响另一个线程的性能
- 在C++中使用cURL和多线程
- 为什么我的C#代码在调用回C++COM直到Task时会暂停.等待/线程.加入
- 在cuda线程之间共享大量常量数据
- 每个线程 C++ 保护以防止重入函数调用
- 死锁使用 std::mutex 来保护多个线程中的 cout
- 通过为每个线程独占使用对象(不在线程之间共享)是保护该类的成员函数所必需的
- C++,如何创建线程限制/受保护的变量和函数
- 多线程设计,在C 中保护全球成员
- 在多线程环境中使用atomic保护两个变量
- 我需要保护一个由一个线程编写并由多个线程读取的变量吗
- 在C++类中构建互斥保护的线程安全方法
- 变量的线程保护
- 多线程:我需要用只读方法保护我的变量吗
- 全局变量构造函数/析构函数是否需要线程保护
- C++11中的线程:接近锁保护的更好方法
- 保护方法内的Boost线程函数
- 无法获取 std::mutex 以正确保护线程访问
- 我需要在多线程环境中保护对STL容器的读取访问吗