我想实现以下内容
1.两个线程:producer
(可更改共享变量a
)、consumer
(等待共享变量更改)
1.我想使用atomic来同步线程
问题-我使用int a;
和std::atomic<int> a;
运行代码,但在100%的情况下,我在PC上得到相同的结果。
calculate_val
process 1
我怎样才能看到有原子和没有原子的代码变化?
using namespace std;
atomic<int> a; // I was replacing with int a; and always have the same result
int val;
int calculate_val() {
cout << "calculate_val " << endl;
return 1;
}
void process(int val) {
cout << "process " << val << endl;
}
void threadProducer() {
val = calculate_val();
a = 1;
}
void threadConsumer() {
while (!a) {
}
process(val);
}
int main() {
thread t2(threadConsumer);
thread t1(threadProducer);
t2.join(); // was trying to change order
t1.join();
return 0;
}
1条答案
按热度按时间envsm3lx1#
你的场景太简单了。在一个具有强有序内存语义的体系结构上(例如x86及其后代,如果你提到“我的PC”,这可能就是你正在使用的),编译器优化关闭,只要编译器不在函数调用之前重新排序
threadProducer
的a = 1;
(它没有理由这样做),不缓存while (!a)
测试的a
值,不消除while(a){}
循环,原子不会有什么不同。如果没有原子,您现有的代码可能会失败:
1.在具有弱序存储语义的机器上(对
a
和val
的写入可以以任何顺序在threadConsumer
中变为可见,并且它们变为可见可能需要任意长的时间)我怀疑iostream
库的内置锁定以及它 Package 的Cx 1 m9n1x可能会触发缓存刷新,因此,您试图“观察”争用的I/O实际上是在“改变"行为。1.在任何机器上,如果编译器选择将
a
的值缓存在threadConsumer
中以提高效率(可以缓存非volatile
、非atomic
值以保存开销,因为假设它们仅从一个线程访问,并且加载线程不会更改它)。1.在任何机器上,如果编译器decides to eliminates the
while (a) {}
loop,由于非原子a
可能会创建一个无限循环,如果按照#2中的建议缓存。1.在任何一台机器上,如果编译器选择将
a = 1;
排在val = calculate_val();
之前(因为两行都不依赖于另一行计算的值,所以优化编译器可以选择以任何一种顺序进行),在实践中,给定前面提到的I/O层的锁定,编译器 * 不会 * 交换这些行,但如果I/O被删除,它 * 可以 * 交换。我不会给予一个可能出错的例子,因为粗略的搜索会找到各种各样的例子,说明何时以及为什么使用原子。重要的是要知道,即使在你简单的场景中,你认为没有原子是安全的,但事实并非如此。即使打开优化也可能导致你的代码使用非原子
a
,在x86-64机器上停止运行。并且x86-64已经是简单模式上的线程/原子。