处理乱序执行 [英] Handling out of order execution

查看:84
本文介绍了处理乱序执行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我最近偶然发现了这篇 Wikipedia文章.根据我在多线程方面的经验,我知道由程序能够随时在线程之间切换线程而引起的众多问题.但是,我从不知道编译器和硬件优化可以保证对单个线程有效,但不一定对多线程有效,可以对操作进行重新排序.谁能解释如何正确处理多线程环境中重新排序操作的可能性?

更新:我最初不小心链接到 Out-顺序执行文章,而不是内存障碍文章,该文章提供了更好的解释问题.

解决方案

我将以高级语言解决有关多线程的问题,而不是讨论CPU管道优化.

任何人都可以解释如何在多线程环境中正确处理重新排序的操作吗?

大多数(如果不是全部)现代的高级多线程语言提供了一种结构,用于管理编译器对指令的逻辑执行进行重新排序的潜力.在C#中,它们包括字段级构造(volatile修饰符),块级构造(lock关键字)和命令式构造(Thead.MemoryBarrier).

volatile 应用于字段会导致对CPU/内存中对该字段的所有访问以与在指令序列(源代码)中出现的顺序相同的相对顺序执行. /p>

在一个代码块周围使用 lock 会使所包围的指令序列以与在父代码块中出现的顺序相同的相对顺序执行.

Thread.MemoryBarrier 方法向编译器指示,CPU不得在指令序列中的这一点附近对内存访问进行重新排序.这样可以为特定需求提供更高级的技术.

按照递增的复杂度和性能的顺序描述了上述技术.与所有并发编程一样,确定何时何地应用这些技术是一个挑战.当同步对单个字段的访问时,volatile关键字将起作用,但可能会被认为是过大的.有时您只需要同步写入操作(在这种情况下,ReaderWriterLockSlim可以完成相同的事情,并且性能要好得多).有时您需要快速连续地多次操作该字段,或者您必须检查一个字段并有条件地对其进行操作.在这些情况下,lock关键字是一个更好的主意.有时,您有多个线程在非常松散地同步的模型中操纵共享状态以提高性能(通常不建议这样做).在这种情况下,精心放置的内存屏障可以防止在线程中使用陈旧和不一致的数据.

I recently stumbled upon this Wikipedia article. From my experience with multi-threading I am aware of the multitude of issues caused by the program being able to switch threads between threads at any time. However, I never knew that compiler and hardware optimisations could reorder operations in a way that is guaranteed to work for a single thread, but not necessarily for multi-threading. Can anyone explain how to correctly deal with the possibility of reordered operations in a multi-threaded environment?

UPDATE: I originally had accidentally linked to the Out-of-Order Execution article instead of the Memory barrier article, which has a better explanation of the problem.

解决方案

I will address your question as one about multithreading in a high-level language, rather than discussing CPU pipeline optimization.

Can anyone explain how to correctly deal with the possibility of reordered operations in a multi-threaded environment?

Most, if not all, modern high-level multithreaded languages provide constructs for managing this potential for the compiler to reorder the logical execution of instructions. In C#, these include field-level constructs (volatile modifier), block-level constructs (lock keyword), and imperative constructs (Thead.MemoryBarrier).

Applying volatile to a field causes all access to that field in the CPU/memory to be executed in the same relative order in which it occurs in the instruction sequence (source code).

Using lock around a block of code causes the enclosed instruction sequence to be executed in the same relative order in which it occurs in the parent block of code.

The Thread.MemoryBarrier method indicates to the compiler that the CPU must not reorder memory access around this point in the instruction sequence. This enables a more advanced technique for specialized requirements.

The techniques above are described in order of increasing complexity and performance. As with all concurrency programming, determining when and where to apply these techniques is the challenge. When synchronizing access to a single field, the volatile keyword will work, but it could prove to be overkill. Sometimes you only need to synchronize writes (in which case a ReaderWriterLockSlim would accomplish the same thing with much better performance). Sometimes you need to manipulate the field multiple times in quick succession, or you must check a field and conditionally manipulate it. In these cases, the lock keyword is a better idea. Sometimes you have multiple threads manipulating shared state in a very loosely-synchronized model to improve performance (not typically recommended). In that case, carefully placed memory barriers can prevent stale and inconsistent data from being used in threads.

这篇关于处理乱序执行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆