静态局部变量中的争用条件

Race conditions in static local variables

本文关键字:争用条件 局部变量 静态      更新时间:2023-10-16

我目前正在阅读有效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()而不是tfstempDir .也就是说,它们使用返回对对象的引用的函数 而不是使用对象本身。

此方案规定的引用返回函数始终是 简单:在第 1 行定义并初始化一个本地静态对象,返回 它在第 2 行。这种简单性使它们成为 内联,特别是如果它们经常被调用(请参阅第 30 项(。上 另一方面,这些函数包含静态对象的事实 使它们在多线程系统中出现问题。再说一遍,任何种类 非常量静态对象(本地或非本地(在等待时遇到问题 在存在多个线程的情况下发生。一种处理方式 这样的麻烦是手动调用所有引用返回 在程序的单线程启动部分期间的函数。 这消除了与初始化相关的争用条件。

本节已过时。C++03标准没有提到线程,所以当C++实现添加线程时,他们在语言结构的线程安全方面做了任何他们想做的事情。一个常见的选择是不确保静态局部变量的线程安全初始化。

在 C++11 中,局部静态变量保证只初始化一次,即程序的控制流第一次通过其声明时,即使这在多个线程上并发发生6.7/4

允许实现在允许在命名空间作用域 (3.6.2( 中静态初始化具有静态或线程存储持续时间的变量的相同条件下,使用静态或线程存储持续时间执行其他块范围变量的早期初始化。否则,此类变量在控件第一次通过其声明时初始化;此类变量在其初始化完成后被视为已初始化。如果初始化通过引发异常退出,则初始化未完成,因此下次控件进入声明时将再次尝试初始化。如果在初始化变量时控件并发进入声明,则并发执行应等待初始化完成。

即便如此,这也只能确保初始化是安全的。如果计划同时使用从多个线程返回的FileSystemFileSystem本身必须提供线程安全操作。