【问题标题】:Race conditions in static local variables静态局部变量中的竞争条件
【发布时间】:2014-05-25 13:55:21
【问题描述】:

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

此方案规定的引用返回函数总是 简单:在第 1 行定义并初始化一个本地静态对象,返回 它在第 2 行。这种简单性使它们成为 内联,尤其是当它们被频繁调用时(参见条款 30)。在 另一方面,这些函数包含静态对象的事实 使它们在多线程系统中出现问题。 再一次,任何种类 非常量静态对象(本地或非本地)的等待很麻烦 在存在多个线程的情况下发生。一种处理方式 这样的麻烦是手动调用所有的引用返回 在程序的单线程启动部分运行。 这消除了与初始化相关的竞争条件。

【问题讨论】:

标签: c++ multithreading initialization singleton race-condition


【解决方案1】:

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

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

在允许实现在命名空间范围内静态初始化具有静态或线程存储持续时间的变量的相同条件下,允许实现对具有静态或线程存储持续时间的其他块范围变量进行早期初始化(3.6.2 )。否则,此类变量在控件第一次通过其声明时被初始化;这样的变量在其初始化完成时被认为已初始化。如果初始化抛出异常退出,说明初始化未完成,下次控件进入声明时会再次尝试。如果控制在变量初始化的同时进入声明,则并发执行等待初始化完成。

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

【讨论】:

    猜你喜欢
    • 2017-07-13
    • 1970-01-01
    • 2010-10-09
    • 1970-01-01
    • 2019-03-03
    • 2012-04-29
    • 2019-03-21
    • 2012-04-23
    • 1970-01-01
    相关资源
    最近更新 更多