C++ 全局变量构造函数/析构函数是否需要线程保护?

C++ 全局变量构造函数/析构函数是否需要线程保护?,c++,multithreading,thread-safety,C++,Multithreading,Thread Safety,如果我有一个类,其唯一目的是拥有全局静态实例(以确保其构造函数中的代码在main之前运行),并且它使用一个类静态变量,那么是否需要通过互斥来保护对该变量的访问 举个例子有助于: class WinSock { public: WinSock() { if(!(inst++)) //winsock init } ~WinSock() { if(!--inst) //winsock deactivate } private: sta

如果我有一个类,其唯一目的是拥有全局
静态
实例(以确保其构造函数中的代码在
main
之前运行),并且它使用一个类
静态
变量,那么是否需要通过互斥来保护对该变量的访问

举个例子有助于:

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++标准P3.6.2:

如果程序启动线程(30.3),则 变量的初始化不按顺序排列 在不同的转换单位中定义的变量。否则 变量的初始化是不确定的 初始化在不同转换中定义的变量 单位

不确定的顺序意味着初始化不会有任何特定的顺序,但不会重叠,因此不需要任何额外的保护措施。不排序意味着不同编译UNI中的构造函数可能重叠,因此需要线程安全


第三,你需要这样做吗?您是否有其他在构造函数中使用winsock的静态对象?我真的想不出任何其他理由来这样做。

首先,我不认为
private:static int inst=0是一个有效的构造,”我的编译器大声抱怨道-如果为了简单起见,您忽略了在项目中的一些.cpp文件中有类似于
int-WinSock::inst=0的内容,那么就没有问题了。如果您的项目根本无法编译,那么很可能所有转换单元都会使用不同的变量,从而导致错误的行为

其次,如果任何静态对象构造函数创建了一个新线程,那么您需要使代码线程安全。从C++标准P3.6.2:

如果程序启动线程(30.3),则 变量的初始化不按顺序排列 在不同的转换单位中定义的变量。否则 变量的初始化是不确定的 初始化在不同转换中定义的变量 单位

不确定的顺序意味着初始化不会有任何特定的顺序,但不会重叠,因此不需要任何额外的保护措施。不排序意味着不同编译UNI中的构造函数可能重叠,因此需要线程安全


第三,你需要这样做吗?您是否有其他在构造函数中使用winsock的静态对象?我真的想不出任何其他理由这样做。

鉴于您描述的特定场景,不添加同步也可以

您担心的是Winsock在运行
main
之前(之后)被初始化(和反初始化),这是肯定的。该代码也保证只从一个线程调用一次。这(事实上只有一个线程)使得同步毫无用处


假设其他静态全局对象使用Winsock(无论它们是否生成线程),这当然是不安全的,但使用互斥也不会更安全。初始化在
main

因此,没有静态全局对象可以使用此构造以安全、定义良好的方式使用Winsock,因为无论哪种方式,您都不知道初始化是否首先发生。同步它不会改变这个细节


注意:不允许在类声明中初始化
inst

根据您描述的特定场景,不添加同步即可

您担心的是Winsock在运行
main
之前(之后)被初始化(和反初始化),这是肯定的。该代码也保证只从一个线程调用一次。这(事实上只有一个线程)使得同步毫无用处


假设其他静态全局对象使用Winsock(无论它们是否生成线程),这当然是不安全的,但使用互斥也不会更安全。初始化在
main

因此,没有静态全局对象可以使用此构造以安全、定义良好的方式使用Winsock,因为无论哪种方式,您都不知道初始化是否首先发生。同步它不会改变这个细节


注意:类声明中的
inst
初始化是不允许的。

我没有看到在ctor或dtor之外使用
inst
,类代码是否完整?如果都在一个标题中,您不会遇到许多不同的
unusedWinSockVar
的问题吗?如果它只定义了一个未使用的变量,为什么它必须包含在头文件中?任何使用
WinSock
的文件都会包含这个头文件?
unusedWinSockVar
是否应该在源文件中声明(为库提供内容)?@didierc确实如此