gpt4 book ai didi

c++ - 仔细检查 C++ : new to a temp pointer, 上的锁定,然后将其分配给实例

转载 作者:塔克拉玛干 更新时间:2023-11-03 01:25:44 25 4
gpt4 key购买 nike

下面的单例实现有什么问题吗?

Foo& Instance() {
if (foo) {
return *foo;
}
else {
scoped_lock lock(mutex);

if (foo) {
return *foo;
}
else {
// Don't do foo = new Foo;
// because that line *may* be a 2-step
// process comprising (not necessarily in order)
// 1) allocating memory, and
// 2) actually constructing foo at that mem location.
// If 1) happens before 2) and another thread
// checks the foo pointer just before 2) happens, that
// thread will see that foo is non-null, and may assume
// that it is already pointing to a a valid object.
//
// So, to fix the above problem, what about doing the following?

Foo* p = new Foo;
foo = p; // Assuming no compiler optimisation, can pointer
// assignment be safely assumed to be atomic?
// If so, on compilers that you know of, are there ways to
// suppress optimisation for this line so that the compiler
// doesn't optimise it back to foo = new Foo;?
}
}
return *foo;
}

最佳答案

不,您甚至不能假设 foo = p; 是原子的。它可能加载 32 位指针的 16 位,然后在加载其余部分之前被换出。

如果此时另一个线程潜入并调用 Instance(),您将被 toast ,因为您的 foo 指针无效。

为了真正的安全,您必须保护整个测试和设置机制,即使这意味着即使在构建指针之后也要使用互斥体。换句话说(我假设 scoped_lock() 会在超出范围时释放锁(我对 Boost 没有什么经验)),比如:

Foo& Instance() {
scoped_lock lock(mutex);
if (foo != 0)
foo = new Foo();
return *foo;
}

如果您不想要互斥量(大概出于性能原因),我过去使用的一个选项是在线程开始之前构建所有单例。

换句话说,假设您拥有该控制权(您可能没有),只需在启动其他线程之前在 main 中为每个单例创建一个实例。然后根本不要使用互斥锁。那时你不会有线程问题,你可以只使用规范的 don't-care-about-threads-at-all 版本:

Foo& Instance() {
if (foo != 0)
foo = new Foo();
return *foo;
}

而且,是的,这确实会使您的代码对那些懒得阅读您的 API 文档但(恕我直言)他们应得的一切的人来说更加危险:-)

关于c++ - 仔细检查 C++ : new to a temp pointer, 上的锁定,然后将其分配给实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3498998/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com