Dyl*_*ier 3 c++ multithreading atomic thread-safety
从技术上来说,似乎需要std::atomic根据标准保护多个线程读取/写入的所有数据,但对于复杂数据初始化的情况来说,这似乎很奇怪。对于 C++ 内存模型,以下未定义行为或使用锁是否可以解决问题?
class Foo {
public:
int x;
int y;
static Foo* GetFoo();
private:
static std::mutex sm_lock;
static Foo* sm_foo;
};
std::mutex Foo::sm_lock;
Foo* sm_foo = nullptr;
Foo* Foo::GetFoo() {
std::lock_guard<std::mutex> guard(sm_lock);
if (!sm_foo) {
sm_foo = new Foo();
if (sm_foo) {
sm_foo->x = 42;
sm_foo->y = 11;
}
}
return sm_foo;
}
Run Code Online (Sandbox Code Playgroud)
我知道在实践中这几乎总是适用于 x86_64,但是内存排序较弱的平台又如何呢?
即使我已经使用 std::mutex 来保护访问,从技术上讲是否需要 std::atomic ?
不,互斥锁使其安全 - 但您不需要sm_foo在 后检查是否为非空new。new(如您的示例中所使用的)如果失败将引发异常:
Foo* Foo::GetFoo() {
std::lock_guard<std::mutex> guard(sm_lock);
if (!sm_foo) {
sm_foo = new Foo();
sm_foo->x = 42; // sm_foo can't be a null pointer here
sm_foo->y = 11;
}
return sm_foo;
}
Run Code Online (Sandbox Code Playgroud)
更好的方法是根本不使用指针。这不需要互斥锁,因为实例化是线程安全的(因为该语言中引入了线程):
class Foo {
public:
int x;
int y;
static Foo& GetFoo();
private:
// if it's supposed to be a singleton:
Foo(int X, int Y) : x(X), y(Y) {}
Foo(const Foo&) = delete;
Foo(Foo&&) = delete;
Foo& operator=(const Foo&) = delete;
Foo operator=(Foo&&) = delete;
~Foo() = default;
};
Foo& Foo::GetFoo() {
static Foo sm_foo{42,11}; // thread safe instantiation
return sm_foo;
}
Run Code Online (Sandbox Code Playgroud)
如果您确实想GetFoo()返回一个指针,那没问题(尽管更常见的是返回对实例的引用):
class Foo {
// ...
static Foo* GetFoo();
};
Foo* Foo::GetFoo() {
static Foo sm_foo{42,11}; // still a thread safe instantiation
return &sm_foo;
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
117 次 |
| 最近记录: |