sbi*_*sbi 19 c++ concurrency multithreading static-initialization
这个问题让我质疑我多年来一直遵循的做法.
对于函数本地静态const对象的线程安全初始化,我保护对象的实际构造,但不保护引用它的函数本地引用的初始化.像这样的东西:
namespace {
const some_type& create_const_thingy()
{
lock my_lock(some_mutex);
static const some_type the_const_thingy;
return the_const_thingy;
}
}
void use_const_thingy()
{
static const some_type& the_const_thingy = create_const_thingy();
// use the_const_thingy
}
Run Code Online (Sandbox Code Playgroud)
这个想法是锁定需要时间,如果引用被多个线程覆盖,那么无关紧要.
如果是的话,我会感兴趣的
我想知道这个的原因是我想知道我是否可以保留代码,或者我是否需要回去修复它.
对于探究的头脑:
我使用的许多这样的函数本地静态const对象是在首次使用时从const数组初始化并用于查找的映射.例如,我有一些XML解析器,其中标记名称字符串映射到enum值,因此我可以稍后switch覆盖标记的enum值.
由于我得到了一些关于该做什么的答案,但是没有得到我实际问题的答案(见上文1.和2.),我会对此开始赏金.还是那句话:
我不感兴趣,我能做什么,而不是,我真的想知道这个.
rjn*_*son 14
这是我第二次尝试回答.我只回答你的第一个问题:
- 在实践中足够安全吗?
不.当你说明自己时,你只是确保对象创建受到保护,而不是初始化对象的引用.
如果没有C++ 98内存模型且没有来自编译器供应商的显式语句,则无法保证写入代表实际引用的内存以及写入包含初始化标志值的内存(如果是如何实现参考,从多个线程以相同的顺序看到.
正如你也可以说具有相同值覆盖参考几次应该没有语义差异(甚至在一句话撕裂,这通常是不可能的,甚至是不可能在你的处理器架构的存在),但有它重要的一个情况:当程序执行期间第一次调用该函数的多个线程竞争.在这种情况下,这些线程中的一个或多个可以看到在初始化实际引用之前设置的初始化标志.
你的程序中有一个潜在的错误,你需要修复它.至于优化,我确信除了使用双重检查锁定模式之外还有很多.
这是我的看法(如果真的你不能在线程启动之前初始化它):
我已经看过(和使用过)这样的东西来保护静态初始化,使用boost :: once
#include <boost/thread/once.hpp>
boost::once_flag flag;
// get thingy
const Thingy & get()
{
static Thingy thingy;
return thingy;
}
// create function
void create()
{
get();
}
void use()
{
// Ensure only one thread get to create first before all other
boost::call_once( &create, flag );
// get a constructed thingy
const Thingy & thingy = get();
// use it
thingy.etc..()
}
Run Code Online (Sandbox Code Playgroud)
在我的理解中,这种方式所有线程都在boost :: call_once上等待,除了将创建静态变量的线程.它只会创建一次,然后再也不会被调用.然后你再也没有锁了.