在生成访问共享资源的子线程之前,是否应该由父线程锁定对共享资源的访问?
如果我有以下伪代码:
sharedVariable = somevalue;
CreateThread(threadWhichUsesSharedVariable);
理论上,多核CPU是否可以在threadWhichUsesSharedVariable()中执行代码,该代码在父线程写入sharedVariable之前读取它的值?为了从理论上完全避免竞争条件的可能性,代码应该如下所示:
sharedVariableMutex.lock();
sharedVariable = somevalue;
sharedVariableMutex.unlock();
CreateThread(threadWhichUsesSharedVariable);
基本上我想知道线程的产生是否在该点显式地线性化 CPU,并且保证这样做。
我知道线程创建的开销可能需要足够的时间,这在实践中永远不会重要,但我内心的完美主义者害怕理论上的竞争条件。在极端条件下,一些线程或核心可能严重滞后,而其他线程或核心则快速高效地运行,我可以想象,除非有锁,否则执行(或内存访问)的顺序可能远程逆转。
If I have the following psuedocode:
sharedVariable = somevalue;
CreateThread(threadWhichUsesSharedVariable);
Is it theoretically possible for a multicore CPU to execute code in threadWhichUsesSharedVariable() which reads the value of sharedVariable before the parent thread writes to it? For full theoretical avoidance of even the remote possibility of a race condition, should the code look like this instead:
sharedVariableMutex.lock();
sharedVariable = somevalue;
sharedVariableMutex.unlock();
CreateThread(threadWhichUsesSharedVariable);
Basically I want to know if the spawning of a thread explicitly linearizes the CPU at that point, and is guaranteed to do so.
I know that the overhead of thread creation probably takes enough time that this would never matter in practice, but the perfectionist in me is afraid of the theoretical race condition. In extreme conditions, where some threads or cores might be severely lagged and others are running fast and efficiently, I can imagine that it might be remotely possible for the order of execution (or memory access) to be reversed unless there was a lock.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我想说你的伪代码在任何正确运行的情况下都是安全的
多处理器系统。 C++ 编译器无法生成对
sharedVariable
收到正确值之前的CreateThread()
除非它能够向自己证明这样做是安全的。你有保证
您的单线程代码的执行效果相当于完全
未重新排序的线性执行路径。任何“时间扭曲”的系统
在变量赋值之前创建线程被严重破坏。
我不认为将
sharedVariable
声明为 volatile 有任何作用在这种情况下很有用。
I would say that your pseudocode is safe on any correctly functioning
multiprocessor system. The C++ compiler cannot generate a call to
CreateThread()
beforesharedVariable
has received a correct valueunless it can prove to itself that doing so is safe. You are guaranteed
that your single-threaded code executes equivalently to a completely
non-reordered linear execution path. Any system that "time warps" the
thread creation ahead of the variable assignment is seriously broken.
I don't think declaring
sharedVariable
as volatile does anythinguseful in this case.
根据您的示例,如果您使用的是 Java,那么答案将是“否”。在 Java 中,在赋值操作完成之前,线程不可能生成并读取您的值。 在其他一些语言中,情况可能有所不同。
“在多个线程之间共享的变量(例如对象的实例变量)具有由 Java 语言规范保证的对除长整型之外的所有数据类型的原子赋值和双精度...如果一个方法仅由单个变量访问或赋值组成,则无需为了线程安全而使其同步,而且为了性能也有充分理由不这样做。”
参考
如果您的
double
或long
被声明为volatile
,那么您也可以保证该赋值是一个原子操作。更新:
您的示例将在 C++ 中运行,就像在 Java 中运行一样。理论上,即使使用乱序执行,线程生成也无法在分配之前开始或完成。
请注意,您的示例非常具体,在任何其他情况下,建议您确保共享资源受到正确保护。新的 C++ 标准推出了很多原子性的东西,因此您可以将变量声明为原子性的,并且赋值操作将对所有线程可见,而无需锁定。 CAS(比较和设置)是您的下一个最佳选择。
Given your example and if you were using Java then the answer would be "No". In Java it is not possible for the thread to spawn and read your value before the assignment operation is complete. In some other languages this might be a different story.
"Variables shared between multiple threads (e.g., instance variables of objects) have atomic assignment guaranteed by the Java language specification for all data types except longs and doubles... If a method consists solely of a single variable access or assignment, there is no need to make it synchronized for thread-safety, and every reason not to do so for performance."
reference
If your
double
orlong
is declaredvolatile
, then you are also guaranteed that the assignment is an atomic operation.Update:
Your example is going to work in C++ just like it works in Java. Theoretically there is no way that the thread spawning will begin or complete before the assignment, even with Out of Order Execution.
Note that your example is VERY specific and in any other case it is recommended that you ensure the shared resource is protected properly. The new C++ standard is coming out with a lot of atomic stuff, so you could declare your variable as atomic and the assignment operation will be visible to all threads without the need of locking. CAS (compare and set) is a your next best option.