对于互斥锁lock()
,标准的mentions:
同一个互斥锁上的先前unlock()操作与此操作同步(如std :: memory_order中所定义)。
此answer试图根据标准解释synchronize-with
的含义。但是,该定义似乎没有明确指定。
我的主要问题是,我能否获得此输出:
x: 1
y: 2
对于以下代码,由于线程A中的内存重新排序?如果x
解锁后A
锁定,是否可以保证B
遵守B
中对A
的写操作?
std::mutex mutex;
int x = 0, y = 0;
int main() {
std::thread A{[] {
x = 1;
std::lock_guard<std::mutex> lg(std::mutex);
y = 0;
}};
std::thread B{[] {
std::lock_guard<std::mutex> lg(std::mutex);
y = x + 2;
}};
A.join();
B.join();
std::cout << "x: " << x << std::endl;
std::cout << "y: " << y << std::endl;
}
如果不是,根据标准的哪一部分?换句话说,我们可以假设锁定/解锁之间存在顺序一致性吗?
我也看到过这个related问题,但这是用于单独的互斥锁的。
与同步关系已明确定义。该标准规定以下内容:
某些库调用与另一个线程执行的其他库调用同步。例如,原子存储发行版与从其存储中获取其值的负载获取同步。 [...] [注意:同步操作的规范定义了何时读取另一个写入的值。对于原子对象,定义很明确。给定互斥锁上的所有操作都以单个总顺序发生。每次获取互斥锁时,都会“读取”最后一个互斥锁版本中写入的值。 —尾注]
进一步:
“看到”释放操作B存储的值,则A与B同步。考虑一个自旋锁,您只需要一个原子bool标志。所有操作都在该标志上进行。为了获取锁,您已使用原子性的read-modify-write操作设置了该标志。原子对象上的所有修改都完全按照修改顺序排序,并且可以确保RMW操作始终读取在与该RMW操作相关联的写入之前写入的最后一个值(按修改顺序)。对原子对象M执行释放操作的原子操作A与对M执行获取操作并从其取值的原子操作B同步释放中的任何副作用以[[A ..]为首的序列
换句话说,如果获取操作A
由于这种保证,对于锁定/解锁操作使用获取/释放语义就足够了,因为成功的锁定操作总是“看到”由先前的解锁写入的值。
关于您的问题:
x
是否保证可以观察到A
中对B
的写入如果
? 重要的是“如果B
解锁后A
锁定B
解锁后A
锁定”!如果可以保证,则是,B
的锁定操作与A
的解锁同步,从而建立事前关联。因此,B
将观察A
的写入。但是,您的代码不能保证B
在A
之后锁定,因此您有潜在的数据争用,这将导致未定义的行为,如@ReinstateMonica正确指出的那样。