我目前正在阅读有效的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
。也就是说,它们使用返回对对象的引用的函数,而不是使用对象本身。此方案规定的返回引用的函数始终很简单:在第1行定义和初始化本地静态对象,然后在第2行返回它。这种简单性使其成为内联的极佳候选对象,尤其是在经常调用它们的情况下(请参阅第30条) )。另一方面,这些函数包含静态对象的事实使它们在多线程系统中成为问题。再说一遍,在存在多个线程的情况下,任何一种非const静态对象(本地或非本地)都很难等待发生。解决此类问题的一种方法是在程序的单线程启动部分期间手动调用所有返回参考的函数。这消除了与初始化相关的竞争条件。
本节已过时。C ++ 03标准没有提到线程,因此,当C ++实现添加它们时,它们就语言构造的线程安全性做了他们想做的事情。一个常见的选择是不确保静态局部变量的线程安全初始化。
在C ++ 11中,保证局部静态变量只能被初始化一次,这是程序的控制流第一次通过它们的声明时,即使这在多个线程上同时发生6.7/4
:
允许实现以静态或线程存储持续时间对其他块作用域变量进行早期初始化,其条件与允许实现以静态或线程存储持续时间在命名空间范围内静态初始化变量的条件相同(3.6.2)。否则,该变量将在控件第一次通过其声明时进行初始化;否则,它将被初始化。这样的变量在初始化完成后被视为已初始化。如果初始化由于抛出异常而退出,则说明初始化未完成,因此下次控件进入声明时将再次尝试初始化。如果在初始化变量时控件同时输入声明,则并发执行应等待初始化完成。
即使这样,这也只能确保初始化是安全的。如果计划同时使用FileSystem
从多个线程返回的值,则FileSystem
它本身必须提供线程安全的操作。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句