7

我有一堆线程。他们应该访问一个包含配置数据的单例,该配置数据在创建单例时初始化一次。因此在第一次访问时。所以对单例的进一步操作只是只读的。在这种情况下我需要关键部分吗?

4

5 回答 5

6

似乎因为数据是在第一次访问时延迟创建的,所以指针或对单例的引用是读写的。这意味着您确实需要一个关键部分。

事实上,在这种情况下,在保持惰性初始化的同时避免临界区的愿望是如此普遍,以至于它导致了双重检查锁定反模式的创建。

另一方面,如果您在读取之前急切地初始化您的单例,您将能够避免通过常量指针/引用访问不可变对象的关键部分。

于 2012-11-14T20:18:43.207 回答
1

我理解您的问题,因为您的单例中有延迟初始化。它仅在第一次读取时初始化。

接下来的连续读取是线程安全的。但是初始化期间的并发读取呢?

如果你有这样的情况:

SomeConfig& SomeConfig::getInstance()
{
   static SomeConfig instance;
   return instance;
} 

然后它取决于你的编译器。根据 C++03 中的这篇文章,如果此静态初始化是线程安全的,则取决于实现。

对于 C++11,它是线程安全的 - 请参阅这篇文章的答案,引用:

这样的变量在控制第一次通过其声明时被初始化;这样的变量在其初始化完成时被认为已初始化。[...]如果在初始化变量时控制同时进入声明,则并发执行应等待初始化完成。

值得注意的是,对全局变量的只读访问是线程安全的。

于 2012-11-14T20:25:28.823 回答
0

不会。如果您只是在完全初始化后读取此数据并且数据从未更改,那么就不可能发生竞争条件。

但是,如果数据以任何方式被写入/修改,那么您将需要同步对它的访问,即在写入之前锁定数据。

于 2012-11-14T20:16:21.930 回答
0

如果您只读取一些共享数据,而从不写入,则不需要同步访问。

您只需要在可能同时读取和写入共享数据时进行同步。

于 2012-11-14T20:17:01.863 回答
0

规范中的官方规则是数据竞争是指一个线程可以同时写入一个变量,而另一个线程读取或写入同一个变量。

如果您可以证明必须在任何读者可以阅读之前进行初始化,那么您就不需要同步。这通常通过在创建(或同步)线程之前进行初始化,或者通过使用静态存储变量来完成,C++11 保证了一些同步

于 2013-09-03T15:33:10.630 回答