一个非标准库能避免标准C++中的数据竞争吗?

x6yk4ghg  于 9个月前  发布在  其他
关注(0)|答案(2)|浏览(106)

请考虑以下示例:

bool lock();  // provided by system
bool unlock(); // provided by system
static int v = 0;
//thread 1
void invoke(){
   lock();
   v = 1;  // #1
   unlock();
}
// thread 2
void invoke2(){
   lock();
   v = 2;  // #2
   unlock()
}

字符串
假设lockunlock是系统提供的mutex,如果它们能够建立happen-before关系,则可以防止#1#2产生数据竞争。
求值A发生在求值B之前(或者,等价地,B发生在A之后),如果:

  • A在B之前排序,或
  • 线程间的操作发生在B之前。

对于两个线程中的计算,我们期望同步建立“happen-before”关系。然而,同步是为标准库定义的,例如一些原子操作或std::mutex。标准没有为其他非标准库定义同步概念。因此,从C++标准的Angular 来看,使用lock()unlock时,即使系统提供了同步,我们也无法获得同步。
也就是说,只有标准库才能同步,因为标准明确这么说了?依赖非标准库会导致UB,即使库是系统提供的,API的文档说可以避免数据竞争。

n6lpvg4x

n6lpvg4x1#

该标准没有为其他非标准库定义同步概念。
条目“A is sequenced before B”在这里很重要,因为这意味着你可以有“A inter-thread happens before B,B is sequenced before C,C is sequenced before Z”,因此可以安全地得出“A happens before Z”的结论。
有两种合理的可能性允许第三方库提供与std::mutex类似的同步保证:

  • 第三方库(transitively)使用std中定义的东西,因此标准 does 定义它确实同步。
  • 第三方库(可传递地)使用由实现所定义的东西,该实现将其定义为同步的东西。

lock()unlock()中的同步意味着一个线程的unlock()必须 * 线程间发生在 * 另一个线程的lock()之前。每个lock()在每个分配之前 * 排序,并且它们在每个unlock()之前 * 排序。这意味着一个分配在另一个分配之前 * 发生,并且没有数据竞争。
实现可以自由地做出这样的保证,并且仍然是一致的,因为“以文档化的方式一致地行为”是“未定义行为”的子集

xxe27gdn

xxe27gdn2#

你想太多了。
假设lockunlock是系统提供的互斥量
那么它们的行为就像你的实现文档中指定的那样。
标准对此怎么说并不重要。也许它有一个条款沿着“实现可以自由地使用实现定义的函数添加自己的头”,也许没有。这并不重要,因为所有的实现都这样做。
在实践中,特定函数调用的同步属性可以归结为两件事:

  • 它叫什么指令。
  • 优化器必须知道它不能在这个调用中重新排序指令(某些指令;在某些方向上)。

因为你调用的是一个不透明的函数,优化器必须假设最坏的情况,而不是重新排序它。

相关问题