原子布尔标志能否确保同步?
Can An Atomic Bool Flag Ensure Synchronization?
我在问自己原子布尔就绪标志是否可以确保数据在线程之间同步(我已经读过这个)但没有评论回答我的问题。
例如看这段代码:
#include<atomic>
#include<thread>
class BIG_DATA {
public:
BIG_DATA(){ std::this_thread::sleep_for(std::chrono::seconds(1)); }//some big data to init ......
};
void init_BIG_DATA(BIG_DATA* & location, std::atomic<bool>& flag ) {
if (flag.load())throw("error : data already loaded");
location = new BIG_DATA(); //heavy operation
flag.store(true);
}
class data {
public:
data() {
ready.store(false);
std::thread t = std::thread(init_BIG_DATA,std::ref(_data),std::ref(ready));
t.detach();
}
BIG_DATA* get_data() {
if (ready.load()) return _data;
else return nullptr;
}
private:
BIG_DATA* _data = nullptr;
std::atomic<bool> ready;
};
在这段代码中,如果我有这样的主线:
data d;
while (d.get_data() == nullptr) ; // wait for Big data to be constructed in an other thread
BIG_DATA* BD = d.get_data();
// do somethin with big data
我能确保我用 BIG_DATA* (BD) 做的事情是正确的,并且对象在创建者和工作线程之间同步吗?
此代码线程安全吗?
这里有一个设计问题。查看代码,我看到两个要求:
BIG_DATA 必须初始化,这需要一些时间。
主线程必须在 BIG_DATA 被构造时阻塞。
这就引出了一个问题,既然BIG_DATA的构造只发生在一个线程中,为什么不直接在主线程中创建呢?
在这种情况下,所有与时间同步和变量变化的跨线程传播有关的问题都消失了。
然而,除此之外,这段代码是线程安全的,因为原子的默认内存顺序是 'full sequential consistency'。这意味着写入 BIG_DATA 的指针将 'happen before' 写入保护它的原子,并且该顺序将跨线程传播。
A store operation with this memory order performs the release operation: no memory accesses in the current thread can be reordered after this store. This ensures that all writes in the current thread are visible in other threads that acquire the same atomic variable and writes that carry a dependency into the atomic variable become visible in other threads that consume the same atomic.
我在问自己原子布尔就绪标志是否可以确保数据在线程之间同步(我已经读过这个
例如看这段代码:
#include<atomic>
#include<thread>
class BIG_DATA {
public:
BIG_DATA(){ std::this_thread::sleep_for(std::chrono::seconds(1)); }//some big data to init ......
};
void init_BIG_DATA(BIG_DATA* & location, std::atomic<bool>& flag ) {
if (flag.load())throw("error : data already loaded");
location = new BIG_DATA(); //heavy operation
flag.store(true);
}
class data {
public:
data() {
ready.store(false);
std::thread t = std::thread(init_BIG_DATA,std::ref(_data),std::ref(ready));
t.detach();
}
BIG_DATA* get_data() {
if (ready.load()) return _data;
else return nullptr;
}
private:
BIG_DATA* _data = nullptr;
std::atomic<bool> ready;
};
在这段代码中,如果我有这样的主线:
data d;
while (d.get_data() == nullptr) ; // wait for Big data to be constructed in an other thread
BIG_DATA* BD = d.get_data();
// do somethin with big data
我能确保我用 BIG_DATA* (BD) 做的事情是正确的,并且对象在创建者和工作线程之间同步吗? 此代码线程安全吗?
这里有一个设计问题。查看代码,我看到两个要求:
BIG_DATA 必须初始化,这需要一些时间。
主线程必须在 BIG_DATA 被构造时阻塞。
这就引出了一个问题,既然BIG_DATA的构造只发生在一个线程中,为什么不直接在主线程中创建呢?
在这种情况下,所有与时间同步和变量变化的跨线程传播有关的问题都消失了。
然而,除此之外,这段代码是线程安全的,因为原子的默认内存顺序是 'full sequential consistency'。这意味着写入 BIG_DATA 的指针将 'happen before' 写入保护它的原子,并且该顺序将跨线程传播。
A store operation with this memory order performs the release operation: no memory accesses in the current thread can be reordered after this store. This ensures that all writes in the current thread are visible in other threads that acquire the same atomic variable and writes that carry a dependency into the atomic variable become visible in other threads that consume the same atomic.