问题描述
限时送ChatGPT账号..这个线程是否安全:
class X;
class Once {
public:
Once(X* x) : x_(x) {}
X* Get() {
if (!x_) return NULL;
// all dirty reads end up here.
// This could be any type of scoped lock...
some_scoped_lock lock(m);
// if (!x_) return x_; // omitted because it's a no op
X* ret(x_); // might get NULL if we waited for lock
x_ = NULL; // idempotent
return ret;
}
private:
X *x_;
some_kind_of_mutex m;
// Boilerplate to make all other constructors and default function private
....
}
(我对 c++11 和旧版本都感兴趣)
据我所知,双重检查锁定的问题是在某些内存中对受保护的 var 的写入建模可能会发生并尽早可见.我认为上面的代码没有这个问题,因为新值的有效性没有先决条件.我认为这是正确代码的唯一要求是锁下的所有读取必须相对于构造函数中的写入和锁下的写入来说是干净的.
As I understand it the problem with Double-checked locking is that in some memory models the write to the guarded var can occur and become visible to early. I think the above code doesn't have this issue because there is no precondition for the validity of the new value. I think the only requirement for this to be correct code is that all reads under the lock must be clean with respect to writes in the constructor and writes under the lock.
更新:好的,这似乎引发了未定义行为"陷阱,因此可以合法地做任何事情,包括耗尽您的银行账户.也就是说,是否存在任何会行为不端的情况?
Update: OK, it seems that this invokes the "undefined behavior" pitfall and therefor can legally do anything, including drain your bank account. That said, are there any cases where it will misbehave?
推荐答案
根据 C++11 标准,行为未定义,因为存在数据竞争.更详细地说:线程 A 在行 x_ = NULL
中写入 x_
并且线程 B 在带有 if 的行中从
.这两个操作没有先后顺序.这意味着存在数据竞争,这意味着未定义的行为.x_
读取(!x_) 返回 NULL
According to the C++11 standard, the behavior is undefined, because there is a data race. In more detail: Thread A writes to x_
in the line x_ = NULL
and Thread B reads from x_
in the line with if (!x_) return NULL
. These two operations are not sequenced. That means there is a data race, and that implies undefined behavior.
您应该使用原子类型来避免数据竞争.这在您的示例中非常简单.但是,我认为这个问题更笼统.尽管如此:
You should use an atomic type to avoid the data race. This is very simple in your example. However, I think the question was more general. Nevertheless:
struct Once
{
std::atomic<X*> _x;
explicit Once(X* x) : _x{x} {}
X* Get()
{
return _x.exchange(nullptr, std::memory_order::memory_order_relaxed);
}
};
这篇关于围绕值变为空值的双重检查锁定?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
更多推荐
[db:关键词]
发布评论