Java 表达方式是;a==1?1:0“;用比较加三元运算符表示原子?
快速提问?这条线是用C++和java编写的吗?Java 表达方式是;a==1?1:0“;用比较加三元运算符表示原子?,java,c++,pthreads,atomic,Java,C++,Pthreads,Atomic,快速提问?这条线是用C++和java编写的吗? class foo { bool test() { // Is this line atomic? return a==1 ? 1 : 0; } int a; } 如果有多个线程访问该行,我们最终可能会执行检查 首先a==1,然后更新a,然后返回,对吗 补充:我没有完成课程,当然,还有其他部分更新了…不,它仍然是一个测试,然后是一个集合,然后是一个返回 是的,多线程将是一个问题 只是语法上的糖 return a==1
class foo {
bool test() {
// Is this line atomic?
return a==1 ? 1 : 0;
}
int a;
}
如果有多个线程访问该行,我们最终可能会执行检查
首先a==1,然后更新a,然后返回,对吗
补充:我没有完成课程,当然,还有其他部分更新了…不,它仍然是一个测试,然后是一个集合,然后是一个返回 是的,多线程将是一个问题 只是语法上的糖
return a==1 ? 1 : 0;
这是一种简单的写作方式
if(a == 1)
return 1;
else
return 0;
我看不到任何更新a的代码。但是我想你可以理解。 < P>不,对于C++和java都是。 在Java中,您需要使方法
同步
,并以同样的方式保护a
的其他用途。确保在所有情况下都在同一对象上同步
在C++中,你需要使用保护<代码> A<代码>,可能用来确保在你的函数结束时正确地解锁互斥体。 < P>正确的方法简单地说:不!(适用于Java和C++)
一个不太正确但更实际的答案是:技术上这不是原子的,但在大多数主流体系结构中,至少是C++。 您发布的代码中没有修改任何内容,只测试变量。因此,代码通常会导致单个
测试(或类似)指令访问该内存位置,也就是说,原子指令。该指令将读取缓存线,并且在相应的loaction中会有一个定义良好的值,不管它是什么
然而,这是偶然的,不是你可以信赖的
当另一个线程向该值写入数据时,它通常甚至可以正常工作,这也是偶然发生的。为此,CPU获取缓存线,覆盖缓存线内相应地址的位置,并将整个缓存线写回RAM。测试变量时,获取一个缓存线,该缓存线包含旧值或新值(两者之间没有任何内容)。在任何类型的保证之前都不会发生,但是你仍然可以考虑这个“原子”。
当多个线程同时修改该变量(不是问题的一部分)时,情况要复杂得多。为了使其正常工作,您需要使用C++11中的一些内容,或者使用原子内部结构,或者类似的东西。否则,就很不清楚会发生什么,操作的结果可能是什么——一个线程可能会读取值,增加值并写回,但另一个线程可能会在写回修改后的值之前读取原始值。
这或多或少保证在所有当前平台上都会很糟糕。 < P>不管有没有写,读C++中的非原子类型的值是<强>不<强>原子操作。如果没有写入,那么您可能不关心它是否是原子的;如果其他线程可能正在修改该值,那么您当然会在意。您的问题可以重新表述为:is语句:
a == 1
原子还是非原子?不,它不是原子的,您应该使用std::atomic作为一个函数,或者在某种锁下检查该条件。如果整个三元运算符是原子的或不是原子的,在本文中并不重要,因为它不会改变任何东西。如果您在问题中的意思是,在本规范中:
bool flag = somefoo.test();
标志与A==1一致,如果你的问题中的全三元运算符是原子的,则它是不相关的。< /P> < P>不,它不是原子的(一般的),虽然它可以在某些体系结构中(例如C++中,如果整数是对齐的,除非它强迫它不对齐),否则< /P>
考虑以下三个线程:
// thread one: // thread two: //thread three
while (true) while (true) while (a) ;
a = 0xFFFF0000; a = 0x0000FFFF;
如果对a
的写入不是原子的(例如,英特尔Ifa
未对齐,并且为了便于讨论,两条连续缓存线中的每一条都有16位)。现在,虽然第三个线程似乎永远无法退出循环(a
的两个可能值都不是零),但事实是赋值不是原子的,线程2可以将较高的16位更新为0,线程3可以在线程2获得完成更新的时间之前将较低的16位读取为0,从循环中走出来
整个条件与问题无关,因为返回的值是线程的本地值。这里有很多很好的答案,但没有一个提到Java中需要将a
标记为volatile
如果没有使用其他同步方法,但其他线程可以更新a
,则这一点尤为重要。否则,您可能正在读取旧值a
请考虑以下代码:
bool done = false;
void Thread1() {
while (!done) {
do_something_useful_in_a_loop_1();
}
do_thread1_cleanup();
}
void Thread2() {
do_something_useful_2();
done = true;
do_thread2_cleanup();
}
这两个线程之间的同步是使用布尔变量done完成的。这是同步两个线程的错误方法
在x86上,最大的问题是编译时优化
编译器可以将do_something_有用的_2()的部分代码移到“done=true”下面。
编译器可以将do_thread2_cleanup()的部分代码移到“done=true”上方。
如果dou\u something\u有用的\u在\u a\u loop\u 1()中没有修改“done”,编译器可能会按以下方式重新写入Thread1:
if (!done) {
while(true) {
do_something_useful_in_a_loop_1();
}
}
do_thread1_cleanup();
所以Thread1永远不会退出
在x86以外的体系结构上,缓存效应或无序指令执行可能会导致其他微妙的问题
大多数种族检测器将检测这种种族
此外,大多数动态竞争检测器将报告打算与此bool同步的内存访问上的数据竞争
(即,在“做一些有用的事情”和“做线程1”和“清理”)之间)
要解决这种竞争,您需要使用编译器和/或内存障碍(如果您不是专家,只需使用锁)。a
不会以任何方式更新,那么为什么synchronized
会有帮助呢?@JoachimIsaksson理论上这个类有更多内容,但是的,有