如果我在运行时强制执行冲突表达式之间的 '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 行为。
例如,我设计了一个客户端-服务器系统,如下所示:
服务器规格
它将使用 2 个线程(线程 A 和线程 B)。
两个线程将共享一个初始化为 0 的全局 int 变量。
它将在 2 个端口(端口 A 和端口 B)上监听客户端消息。
线程 A 将使用端口 A,线程 B 将使用端口 B。
线程A/B伪代码:
while(true) {
Receive message on the connected socket(port A in case of Thread A and port B for thread B).
Increment the shared global variable.
Send an acknowledgement to the client.
}
- 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.
客户规格
它将是单线程的
它将连接到服务器的上述2个端口。
它将交替向服务器的两个端口发送消息,从端口 A 开始。
收到上一条消息的确认后才会发送下一条消息
伪代码:
while(true) {
Send message to port A of server.
Receive acknowledgement of the above message.
Send message to port B of server.
Receive acknowledgement of the above message.
}
在上面的例子中,服务器的线程A和线程B共享一个全局变量。有 2 个冲突的表达式(共享变量的增量操作),我没有使用任何语言提供的同步机制。但是,我在 运行-time 强制执行排序。我知道编译器不知道 运行 时间但在 运行 时间,因为我确保线程 A 和线程 B 永远不能同时访问变量。
所以我不确定这是否属于数据竞争的范畴。
基本上我的查询是:
是否有必要在编译时而非 运行 时强制执行排序以避免数据竞争?上述服务器的代码是否属于具有数据竞争的程序类别?
当线程在不使用 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?
否,如果您等待确认。但是你正行走在非常薄的冰上。如果一段时间后,您将两个请求一起发送,甚至一个接一个地发送而不等待确认怎么办?咔嚓。内核中的调度程序可以选择它想要执行的任何线程。
此外,
- 共享变量是导致多线程代码中各种难以跟踪的崩溃的原因。避开它。
- 使用消息传递。做所有共享变量可以做的事情的更简洁的方法。更容易推理。
编辑:
关于强制执行除 C++ 同步内置命令之外的顺序的问题,您可以使用 OS 的同步原语,您正在使用 windows、posix,随便什么。那将是您将使用的 C 函数和结构,但它在技术上也适用于 C++
根据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 行为。
例如,我设计了一个客户端-服务器系统,如下所示:
服务器规格
它将使用 2 个线程(线程 A 和线程 B)。
两个线程将共享一个初始化为 0 的全局 int 变量。
它将在 2 个端口(端口 A 和端口 B)上监听客户端消息。
线程 A 将使用端口 A,线程 B 将使用端口 B。
线程A/B伪代码:
while(true) { Receive message on the connected socket(port A in case of Thread A and port B for thread B). Increment the shared global variable. Send an acknowledgement to the client. }
- 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.
客户规格
它将是单线程的
它将连接到服务器的上述2个端口。
它将交替向服务器的两个端口发送消息,从端口 A 开始。
收到上一条消息的确认后才会发送下一条消息
伪代码:
while(true) { Send message to port A of server. Receive acknowledgement of the above message. Send message to port B of server. Receive acknowledgement of the above message. }
在上面的例子中,服务器的线程A和线程B共享一个全局变量。有 2 个冲突的表达式(共享变量的增量操作),我没有使用任何语言提供的同步机制。但是,我在 运行-time 强制执行排序。我知道编译器不知道 运行 时间但在 运行 时间,因为我确保线程 A 和线程 B 永远不能同时访问变量。
所以我不确定这是否属于数据竞争的范畴。
基本上我的查询是:
是否有必要在编译时而非 运行 时强制执行排序以避免数据竞争?上述服务器的代码是否属于具有数据竞争的程序类别?
当线程在不使用 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?
否,如果您等待确认。但是你正行走在非常薄的冰上。如果一段时间后,您将两个请求一起发送,甚至一个接一个地发送而不等待确认怎么办?咔嚓。内核中的调度程序可以选择它想要执行的任何线程。
此外,
- 共享变量是导致多线程代码中各种难以跟踪的崩溃的原因。避开它。
- 使用消息传递。做所有共享变量可以做的事情的更简洁的方法。更容易推理。
编辑: 关于强制执行除 C++ 同步内置命令之外的顺序的问题,您可以使用 OS 的同步原语,您正在使用 windows、posix,随便什么。那将是您将使用的 C 函数和结构,但它在技术上也适用于 C++