我目前正在阅读Effective C ++。有一个关于使用静态局部变量的部分,它说如果多个线程访问一个静态变量,那么在该变量初始化期间可能存在竞争条件。
至少这是我的解释。这是真的?例如,在C#中,类静态变量的初始化永远不会有竞争条件。
例如,此代码在静态变量初始化期间是否具有竞争条件?
FileSystem& tfs()
{
static FileSystem fs;
return fs;
}
以下是书中的除外。
这是适用于tfs和tempDir的技术:
class FileSystem { ... }; // as before FileSystem& tfs() // this replaces the tfs object; it could static in the FileSystem class { static FileSystem fs; // define and initialize a local static object return fs; // return a reference to it }
class Directory { ... }; // as before Directory::Directory( params ) // as before, except references to tfs are now to tfs() { ... std::size_t disks = tfs().numDisks(); ... } Directory& tempDir() // this replaces the tempDir object; it could be static in the Directory class { static Directory td; // define/initialize local static object return td; // return reference to it }
此修改后的系统程序的客户端与以前一样, 除了他们现在引用
tfs()
和tempDir()
而不是tfs
和tempDir
。也就是说,它们使用函数返回对象的引用 而不是使用对象本身。此方案规定的参考返回功能始终如此 simple:在第1行定义并初始化本地静态对象,返回 它在第2行。这种简单性使它们成为绝佳的候选者 内联,特别是如果它们被频繁调用(见项目30)。上 另一方面,这些函数包含静态对象 使它们在多线程系统中出现问题。 然后再说一遍 非常量静态对象 - 本地或非本地 - 是等待的麻烦 在存在多个线程时发生。一种方法来处理 这样的麻烦是手动调用所有引用返回 函数在程序的单线程启动部分。 这消除了与初始化相关的竞争条件。
答案 0 :(得分:10)
此部分已过时。 C ++ 03标准没有提到线程,所以当C ++实现添加它们时,它们就语言结构的线程安全性做了他们想做的任何事情。一个常见的选择是不确保静态局部变量的线程安全初始化。
在C ++ 11中,保证本地静态变量只被初始化一次,这是程序控制流第一次通过它们的声明,即使这在多个线程上同时发生6.7/4
:
允许实现在静态或线程存储持续时间内执行其他块范围变量的早期初始化,条件是允许实现在命名空间范围内静态初始化具有静态或线程存储持续时间的变量(3.6.2) )。否则,在第一次控制通过其声明时初始化这样的变量;这样的变量在初始化完成后被认为是初始化的。如果通过抛出异常退出初始化,则初始化未完成,因此下次控制进入声明时将再次尝试初始化。如果控件在初始化变量时同时进入声明,则并发执行应等待初始化完成。
即便如此,这只能确保初始化是安全的。如果您计划同时使用多个线程中返回的FileSystem
,FileSystem
本身必须提供线程安全操作。