我记得读里面的方法声明静态变量不是线程安全的。 (见怎么样Meyer的单?如提到的托德·加德纳 )
Dog* MyClass::BadMethod()
{
static Dog dog("Lassie");
return &dog;
}
我的图书馆生成C ++代码为最终用户来编译作为其应用程序的一部分。 它生成的代码需要在一个线程安全的跨平台的方式来初始化静态变量。 我想使用boost::call_once
以互斥变量初始化但后来最终用户接触到的升压依赖。
是否有我的方式做到这一点不强制对终端用户额外的依赖?
你是正确的像静态初始化不是线程安全的( 这里是一篇文章讨论什么,编译器会把它变成)
目前,没有标准的,线程安全的,便携初始化静态单身的方式。 双重检查锁定可以使用,但你需要潜在非便携式线程库(见讨论这里 )。
这里有几个选项,如果线程安全性是必须的:
- 不要偷懒(加载):静态初始化期间初始化。 这可能是一个问题,如果另一静态调用这个函数在它的构造函数,因为静态初始化的顺序是不确定的(见这里 )。
- 使用升压(如你所说)或洛基
- 滚你支持的平台上自己的单(也许应该避免,除非你是一个线程专家)
- 锁定你需要访问一个互斥体每次。 这可能是非常缓慢的。
实施例1:
// in a cpp:
namespace {
Dog dog("Lassie");
}
Dog* MyClass::BadMethod()
{
return &dog;
}
实施例4:
Dog* MyClass::BadMethod()
{
static scoped_ptr<Dog> pdog;
{
Lock l(Mutex);
if(!pdog.get())
pdog.reset(new Dog("Lassie"));
}
return pdog.get();
}
不知道这是否是你的意思还是没有,但你可以通过调用取消对POSIX系统升压依赖pthread_once
来代替。 我猜你必须做一些事情上的Windows不同,但避免正是为什么升压在首位一个线程库,以及为什么人们支付取决于它的价格。
做任何事情“线程安全”的固有约束与您的线程实现。 你必须依靠的东西 ,即使它只是依赖于平台的内存模型。 这是根本不可能在纯C ++ 03在所有承担任何关于线程,这是语言的范围之内。
你能做到这一点的一种方式,它不需要线程安全互斥是使单文件静态的,而不是静态的功能:
static Dog dog("Lassie");
Dog* MyClass::BadMethod()
{
return &dog;
}
该Dog
实例将在主线程运行之前进行初始化。 文件静态变量有初始化为了一个著名的问题,但只要狗不依赖于另一个转换单元中定义的任何其他静态,这不应该成为关注的问题。
我知道的,确保您不会有像你的非受保护资源的线程问题的唯一办法"static Dog"
是使其所创建的任何线程之前,他们都实例化的要求。
这可能是因为刚刚记录,他们必须调用一个简单MyInit()
做任何事情之前在主线程功能。 然后你构建MyInit()
来实例化和销毁包含这些静态的每种类型的一个对象。
唯一的另一种方法是把另一个限制他们如何使用您生成的代码(使用Boost,Win32的线程,等等)。 无论这些解决方案都是在我看来可以接受的 - 它的好来产生,他们必须遵守规则。
如果他们不遵守载列由你的文档的规则,那么所有的赌注都关闭。 他们必须调用初始化函数或依赖于加速的规则是没有道理给我。
据我所知,只有这个时间已经安全完成,没有互斥体或全局实例的初始化之前是马修·威尔森的不完美的C ++ ,它讨论了如何使用“旋转互斥体”来做到这一点。 我不靠近我对它的副本,所以不能在这个时候任何更精确地告诉你。
IIRC,有内部使用的这种的一些例子STLSoft库,虽然我不能在这个时候记得哪些组件。