【问题标题】:Global static initialization threading全局静态初始化线程
【发布时间】:2013-09-03 18:25:08
【问题描述】:

我有一个用互斥锁保护的集合。初始化后它只会被读取,所以我不需要互斥体。

集合在全局静态初始化器中被初始化和填充。我知道在单个翻译单元中保证全局静态初始化。是否保证全局静态初始化是单线程的?


我有一个受 Schwarz 计数器保护的静态集合,并由其他静态对象的构造函数填充。容器与互斥锁相关联。鉴于集合在main 启动后是只读的,如果我能保证在单个线程中调用静态构造函数,我想摆脱互斥锁。

我的理解是静态初始化顺序通常在单个翻译单元中定义良好,但在翻译单元之间未指定。该标准是否允许静态对象由不同的运行时提供的线程初始化/构造?


施瓦茨计数器:

头文件:

struct Init
{
   Init();
   ~Init();
};
namespace
{
   Init _init;
}
extern std::map<int, std::unique_ptr<...>> &protected;

源文件:

namespace
{
   int init_count;
   std::aligned_storage<sizeof(std::map<int, std::unique_ptr<...>>), alignof(std::map<int, std::unique_ptr<...>>>)> protected_storage;
}
std::map<int, std::uniqe_ptr<...>> &protected = *reinterpret_cast<std::map<int, std::unique_ptr<...>> *>(&protected_storage);
Init::Init()
{
   if (!init_counter++)
   {
      new(&protected_storage) std::map<int, std::unique_ptr<...>>();
   }
}
Init::~Init()
{
   if (!--init_counter)
   {
      protected.~std::map<int, std::unique_ptr<...>>();
   }
}

采集人群:

struct helper
{
   helper(...)
   {
      protected.insert(std::make_pair(...));
   }
};

一个宏被展开,它创建了帮助器的静态实例。

【问题讨论】:

  • 在 C++11 中,静态初始化不会引入数据竞争。
  • 静态初始化是零初始化常量初始化。我认为您在多线程和单线程 static init(非局部变量)之间不会有任何明显的差异。
  • 我们真的是在谈论全局静态初始化器,还是我们也在考虑静态对象的构造器?
  • @KerrekSB 是的,但是您最初的评论指的是什么?如果程序启动线程(因此可能存在数据竞争 AFAIK),则在不同 TU 中具有有序初始化的变量的动态初始化可能是无序的
  • @DyP:好吧,我的意思是(在第一条评论中)“初始化具有静态存储持续时间的对象”。那可能令人困惑。 “静态”意味着太多的东西:-S

标签: c++ c++11


【解决方案1】:

是否保证全局静态初始化是单线程的?

你的意思是动态初始化。不,单线程初始化是明确不保证的。

从 3.6.2 开始:

如果一个程序启动了一个线程(30.3),后续的初始化 相对于在不同翻译中定义的变量的初始化,变量的顺序是无序的 单元。否则,变量的初始化相对于初始化的顺序是不确定的 在不同的翻译单元中定义的变量。如果一个程序启动一个线程,后续的无序 变量的初始化相对于所有其他动态初始化是无序的。否则, 变量的无序初始化相对于其他所有动态是不确定的 初始化

因此,如果您在程序中启动一个线程,那么来自两个不同 TU 的两个不同全局变量理论上可以让它们的构造函数同时从两个不同线程运行。

处理这些问题的最佳方法是将静态存储持续时间变量包装为以下“单例模式”中的局部静态变量:

const T& f()
{
    static T t(a,b,c);
    return t;
}

最新标准保证t 的构造是线程安全的,因此您根本不需要互斥体(至少没有明确指定,编译器会为您生成保护)。

作为一个额外的好处,对象是在第一次调用f 时“延迟”构造的,因此您无需担心初始化顺序。如果多个这样的单例在它们的构造函数中相互调用(当然前提是依赖关系是非循环的),它们将按照工作顺序进行初始化。对于非局部变量,情况并非如此。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-05-22
    • 2010-12-31
    • 2010-10-27
    • 2011-02-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多