如果我在运行时强制执行冲突表达式之间的 'happens before' 关系,这是一场数据竞赛吗?

Is it a data race if I enforce 'happens before' relation between conflicting expressions at runtime?

根据cppreference,

When an evaluation of an expression writes to a memory location and another evaluation reads or modifies the same memory location, the expressions are said to conflict. A program that has two conflicting evaluations has a data race unless:

a) both evaluations execute on the same thread or in the same signal handler, or
b) both conflicting evaluations are atomic operations (see std::atomic), or
c) one of the conflicting evaluations happens-before another (see std::memory_order)

我对c点有点困惑。根据 Anthony Williams 的书(C++ concurrency in action),第 5.1.2 节:

If there’s no enforced ordering between two accesses to a single memory location from separate threads, one or both of those accesses is not atomic, and if one or both is a write, then this is a data race and causes undefined behavior. According to the language standard, once an application contains any undefined behavior, all bets are off; the behavior of the complete application is now undefined, and it may do anything at all

我知道如果我强制执行排序,比如使用 std::mutex,那么(冲突表达式的)多个评估不可能与另一个评估同时发生,那么一切都很好,我的程序将被明确定义。我喜欢将其视为 'compile-time order enforcement'.

我想了解 'run-time order enforcement' 是否足以消除 data-race/undefined 行为。

例如,我设计了一个客户端-服务器系统,如下所示:

服务器规格

  • Please note that, there's no inter-thread synchronisation introduced by the networking library/system calls made in the first and last step of the pseudo code.

客户规格

在上面的例子中,服务器的线程A和线程B共享一个全局变量。有 2 个冲突的表达式(共享变量的增量操作),我没有使用任何语言提供的同步机制。但是,我在 运行-time 强制执行排序。我知道编译器不知道 运行 时间但在 运行 时间,因为我确保线程 A 和线程 B 永远不能同时访问变量。

所以我不确定这是否属于数据竞争的范畴。

基本上我的查询是:

  1. 是否有必要在编译时而非 运行 时强制执行排序以避免数据竞争?上述服务器的代码是否属于具有数据竞争的程序类别?

  2. 当线程在不使用 C++ 语言的同步结构(mutex/futures/atomic)等的情况下共享数据时,是否有一种方法可以在多线程 C++ 程序的编译时强制执行排序

Will the above server's code fall in the category of programs having data race?

是的。

Is there a way to enforce ordering at compile time in a multi-threaded C++ program when threads are sharing data without using C++ language's synchronisation constructs(mutex/futures/atomic) etc.

实施可以提供超出标准要求的额外保证。

Will the above server's code fall in the category of programs having data race?

否,如果您等待确认。但是你正行走在非常薄的冰上。如果一段时间后,您将两个请求一起发送,甚至一个接一个地发送而不等待确认怎么办?咔嚓。内核中的调度程序可以选择它想要执行的任何线程。

此外,

  1. 共享变量是导致多线程代码中各种难以跟踪的崩溃的原因。避开它。
  2. 使用消息传递。做所有共享变量可以做的事情的更简洁的方法。更容易推理。

编辑: 关于强制执行除 C++ 同步内置命令之外的顺序的问题,您可以使用 OS 的同步原语,您正在使用 windows、posix,随便什么。那将是您将使用的 C 函数和结构,但它在技术上也适用于 C++