在标准C++中,非标准库能否避免数据竞争?
先看示例代码:
bool lock(); // 系统提供的API bool unlock(); // 系统提供的API static int v = 0; // 线程1 void invoke(){ lock(); v = 1; // #1 unlock(); } // 线程2 void invoke2(){ lock(); v = 2; // #2 unlock(); }
假设lock()和unlock()是系统提供的互斥锁实现,从功能上看它们能避免v的并发写入冲突,但从C++标准的角度,这里存在合规性疑问:
根据C++标准[intro.races] p10条款的定义:
当满足以下条件时,求值A happens before(等价于B happens after)求值B:
- A在B之前被排序(同一线程内),或
- A线程间happens before B。
线程间的happens-before关系只能通过C++标准库明确规定的同步操作建立,比如std::mutex的加解锁、原子操作的同步语义等。C++标准并未对非标准库的同步原语定义任何同步语义,因此从标准的严格视角来看,哪怕系统提供的lock()/unlock()实际能保证线程安全,它们也无法建立标准认可的happens-before关系,这意味着对v的并发写入仍属于标准定义的数据竞争,进而触发未定义行为(UB)。
核心疑问解答
是否只有标准库能实现标准合规的同步?
是的。C++标准仅承认自身定义的同步机制,非标准库的同步API不在标准的规范范围内,无法提供标准级别的同步保证。依赖系统提供的非标准同步API一定会导致UB吗?
理论上,严格符合C标准的代码中,这类用法属于未定义行为。但实际场景中,大多数主流编译器和平台会对系统原生同步API(比如POSIX的pthread_mutex、Windows的CRITICAL_SECTION)提供隐含的兼容支持:编译器会避免在这些API前后进行非法的指令重排,同时硬件层面的内存屏障也会被正确插入,从而实际避免数据竞争。
但这种支持是平台扩展,而非C标准的强制要求。如果代码需要跨平台的标准合规性,依赖非标准同步原语确实存在风险;但如果是针对特定平台编写,且平台文档明确说明其同步API与C++线程模型兼容,那么实际使用中通常不会出现问题。
内容的提问来源于stack exchange,提问作者xmh0511

