同一互斥锁顺序上的锁定和解锁是否一致?

问题描述 投票:1回答:1

对于互斥锁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问题,但这是用于单独的互斥锁的。

c++ multithreading mutex
1个回答
0
投票

与同步关系已明确定义。该标准规定以下内容:

某些库调用与另一个线程执行的其他库调用同步。例如,原子存储发行版与从其存储中获取其值的负载获取同步。 [...] [注意:同步操作的规范定义了何时读取另一个写入的值。对于原子对象,定义很明确。给定互斥锁上的所有操作都以单个总顺序发生。每次获取互斥锁时,都会“读取”最后一个互斥锁版本中写入的值。 —尾注]

进一步:

对原子对象M执行释放操作的原子操作A与对M执行获取操作并从其取值的原子操作B同步释放中的任何副作用以[[A ..]为首的序列

换句话说,如果获取操作

A

“看到”释放操作B存储的值,则AB同步。考虑一个自旋锁,您只需要一个原子bool标志。所有操作都在该标志上进行。为了获取锁,您已使用原子性的read-modify-write操作设置了该标志。原子对象上的所有修改都完全按照修改顺序排序,并且可以确保RMW操作始终读取在与该RMW操作相关联的写入之前写入的最后一个值(按修改顺序)。

由于这种保证,对于锁定/解锁操作使用获取/释放语义就足够了,因为成功的锁定操作总是“看到”由先前的解锁写入的值。

关于您的问题:

x是否保证可以观察到A中对B的写入

如果B解锁后A锁定

重要的是“如果B解锁后A锁定”!如果可以保证,则是,B的锁定操作与A的解锁同步,从而建立事前关联。因此,B将观察A的写入。但是,您的代码不能保证BA之后锁定,因此您有潜在的数据争用,这将导致未定义的行为,如@ReinstateMonica正确指出的那样。
© www.soinside.com 2019 - 2024. All rights reserved.