应该何时使用Win32 InterlockedExchange功能?

时间:2008-10-16 13:13:51

标签: multithreading winapi

我遇到了函数InterlockedExchange,并想知道何时应该使用此函数。在我看来,在x86处理器上设置32位值应该始终是原子的?
在我想使用该函数的情况下,新值不依赖于旧值(它不是增量操作)。 你能举例说明这种方法是强制性的(我不是在寻找InterlockedCompareExchange)

7 个答案:

答案 0 :(得分:11)

除了编写新值之外,InterlockedExchange还会读取并返回先前的值;整个操作都是原子的。这对lock-free algorithms很有用。

(顺便说一句,32位写入不保证是原子的。例如,考虑写入未对齐并跨越缓存边界的情况。)

答案 1 :(得分:10)

InterlockedExchange是一个写读取 - 它返回前一个值。

这是必要的,以确保另一个线程在您执行之后不会写入不同的值。例如,假设您正在尝试增加变量。您可以读取值,添加1,然后使用InterlockedExchange设置新值。 InterlockedExchange返回的值必须与您最初读取的值匹配,否则另一个线程可能会同时增加它,您需要循环并再试一次。

答案 2 :(得分:4)

在多处理器或多核计算机中,每个核心都有自己的缓存 - 因此每个核心都拥有可能与系统内存内容不同的“视图”。

线程同步机制负责核心之间的同步,有关更多信息,请查看http://blogs.msdn.com/oldnewthing/archive/2008/10/03/8969397.aspx或google获取和发布语义

答案 3 :(得分:3)

设置32位值是原子的,但仅限于设置文字。

b = a是2个操作:

mov         eax,dword ptr [a] 
mov         dword ptr [b],eax 

理论上,第一次和第二次操作之间可能会有一些中断。

答案 4 :(得分:3)

默认情况下,写一个值绝不是原子的。向变量写入值时,会生成多个机器指令。使用现代抢占式操作系统,操作系统可能会切换到写入的各个操作之间的另一个线程。

这在多处理器计算机上更是一个问题,其中多个线程可以同时执行,并尝试同时写入单个内存位置。

互锁操作通过使用专用指令进行写操作来避免这种情况(x86具有针对这种情况的专用指令),它在一条指令中执行读 - 修改 - 写操作。这些指令还锁定所有处理器的内存总线,以确保没有其他正在执行的线程可以同时写入该值。

答案 5 :(得分:2)

InterlockedExchange确保变量的更改及其原始值的返回不会被其他线程中断。

因此,如果'i'是一个int,这些调用(单独采取)不需要在'i'周围进行InterlockedExchange:

a = i;
i = 9;
i = a;
i = a + 9;
a = i + 9;
if(0 == i)

这些陈述都不依赖于'i'的初始和最终值。但是这些以下的呼叫需要在'i'周围进行InterlockedExchange:

a = i++;  //a = InterlockedExchange(&i, i + 1);

没有它,两个运行同一代码的线程可能会获得相同的'i'值分配给'a'或'a'可能会意外跳过两个或更多数字。

if(0 == i++) //if(0 == InterlockedExchange(&i, i + 1))

两个线程都可以执行只发生一次的代码 等

答案 6 :(得分:-1)

哇,这么多相互矛盾的答案。很难筛选谁是对的,谁是错的,以及哪些信息具有误导性。

考虑到上面的半答案,我也不确定答案,但我认为它的工作方式是这样的,我可能错了,找出我是不是很有趣:

  1. 32位读取&写ARE是原子的,但根据你的代码,这可能并不多。
  2. 不要担心不对齐的读/写。必须对齐32位变量的所有32位写入或机器页面错误。
  3. 不要担心在缓存页面的末尾写一个包装,这是不可能发生的。
  4. 如果您需要在一个线程上进行write-then-read,并且您正在另一个线程上编写,那么您需要使用InterlockedExchange。如果您只是在一个线程上读取值,并将其写入另一个线程,那么您不需要使用它,但由于多线程,这些值可能会摇摆不定。