请考虑以下示例:
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()
}
字符串
假设lock
和unlock
是系统提供的mutex
,如果它们能够建立happen-before关系,则可以防止#1
和#2
产生数据竞争。
求值A发生在求值B之前(或者,等价地,B发生在A之后),如果:
- A在B之前排序,或
- 线程间的操作发生在B之前。
对于两个线程中的计算,我们期望同步建立“happen-before”关系。然而,同步是为标准库定义的,例如一些原子操作或std::mutex
。标准没有为其他非标准库定义同步概念。因此,从C++标准的Angular 来看,使用lock()
和unlock
时,即使系统提供了同步,我们也无法获得同步。
也就是说,只有标准库才能同步,因为标准明确这么说了?依赖非标准库会导致UB,即使库是系统提供的,API的文档说可以避免数据竞争。
2条答案
按热度按时间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
类似的同步保证:std
中定义的东西,因此标准 does 定义它确实同步。lock()
和unlock()
中的同步意味着一个线程的unlock()
必须 * 线程间发生在 * 另一个线程的lock()
之前。每个lock()
在每个分配之前 * 排序,并且它们在每个unlock()
之前 * 排序。这意味着一个分配在另一个分配之前 * 发生,并且没有数据竞争。实现可以自由地做出这样的保证,并且仍然是一致的,因为“以文档化的方式一致地行为”是“未定义行为”的子集
xxe27gdn2#
你想太多了。
假设
lock
和unlock
是系统提供的互斥量那么它们的行为就像你的实现文档中指定的那样。
标准对此怎么说并不重要。也许它有一个条款沿着“实现可以自由地使用实现定义的函数添加自己的头”,也许没有。这并不重要,因为所有的实现都这样做。
在实践中,特定函数调用的同步属性可以归结为两件事:
因为你调用的是一个不透明的函数,优化器必须假设最坏的情况,而不是重新排序它。