【发布时间】:2012-11-03 09:47:17
【问题描述】:
我有一堆线程。他们应该访问一个包含配置数据的单例,该配置数据在创建单例时初始化一次。因此在第一次访问时。所以对单例的进一步操作只是只读的。在这种情况下我需要关键部分吗?
【问题讨论】:
标签: c++ multithreading shared-memory critical-section
我有一堆线程。他们应该访问一个包含配置数据的单例,该配置数据在创建单例时初始化一次。因此在第一次访问时。所以对单例的进一步操作只是只读的。在这种情况下我需要关键部分吗?
【问题讨论】:
标签: c++ multithreading shared-memory critical-section
似乎因为数据是在第一次访问时惰性创建的,所以对你的单例的指针或引用是可读写的。这意味着您确实需要一个关键部分。
事实上,在这种情况下保持惰性初始化的同时避免临界区的愿望是如此普遍,以至于它导致了double-checked locking antipattern的创建。
另一方面,如果您要在读取之前急切地初始化单例,则可以避免通过常量指针/引用访问不可变对象的关键部分。 p>
【讨论】:
我理解您的问题,因为您的单例中有延迟初始化。它仅在第一次读取时初始化。
接下来的连续读取是线程安全的。但是初始化期间的并发读取呢?
如果你有这样的情况:
SomeConfig& SomeConfig::getInstance()
{
static SomeConfig instance;
return instance;
}
那么这取决于你的编译器。根据 C++03 中的 post,如果此静态初始化是线程安全的,则取决于实现。
对于 C++11,它是线程安全的 - 请参阅此 post 的答案,引用:
这样的变量在控件第一次通过其声明时被初始化;这样的变量在其初始化完成时被认为已初始化。 [...] 如果在初始化变量时控制同时进入声明,则并发执行将等待初始化完成。
值得注意的是,对全局变量的只读访问是线程安全的。
【讨论】:
没有。如果您只是在完全初始化后读取这些数据,并且数据从不改变,那么就不可能发生竞争条件。
但是,如果数据以任何方式被写入/修改,那么您将需要同步对它的访问,即在写入之前锁定数据。
【讨论】:
如果您只读取了一些共享数据,而从不写入,则不需要同步访问。
您只需要在可能同时读取和写入共享数据时进行同步。
【讨论】:
规范中的官方规则是数据竞争是指一个线程可以同时写入一个变量,而另一个线程读取或写入同一个变量。
如果您可以证明必须在任何阅读器可以阅读之前进行初始化,那么您就不需要同步。这通常通过在创建(或同步)线程之前进行初始化,或者通过使用静态存储变量来完成,C++11 保证了一些同步
【讨论】: