Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/sql-server-2008/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Multithreading 什么时候应该使用Win32 InterlockedExchange函数?_Multithreading_Winapi - Fatal编程技术网

Multithreading 什么时候应该使用Win32 InterlockedExchange函数?

Multithreading 什么时候应该使用Win32 InterlockedExchange函数?,multithreading,winapi,Multithreading,Winapi,我遇到了这个函数,想知道什么时候应该使用这个函数。在我看来,在x86处理器上设置32位值应该始终是原子的 在我想使用函数的情况下,新值不依赖于旧值(它不是增量操作)。 您能否提供一个示例,说明此方法是强制性的(我不寻找InterlocatedCompareExchange)InterlocatedExchange既是写入又是读取--它返回以前的值 这是必要的,以确保另一个线程没有在您刚刚写入不同的值之后写入不同的值。例如,假设您试图增加一个变量。您可以读取该值,添加1,然后使用Interlock

我遇到了这个函数,想知道什么时候应该使用这个函数。在我看来,在x86处理器上设置32位值应该始终是原子的
在我想使用函数的情况下,新值不依赖于旧值(它不是增量操作)。
您能否提供一个示例,说明此方法是强制性的(我不寻找InterlocatedCompareExchange)

InterlocatedExchange
既是写入又是读取--它返回以前的值


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

除了写入新值外,
InterlockedExchange
还读取并返回以前的值;整个操作是原子的。这对我们来说很有用


(顺便说一下,32位写不能保证是原子的。考虑写不对齐和跨缓存边界的情况)。< /P> < P>设置32位值是原子的,但仅当您设置文字时。

b=a是2个操作:

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

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

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


线程同步机制负责核心之间的同步,有关更多信息,请查看google for acquire and release语义,默认情况下,写入值从来都不是原子的。将值写入变量时,会生成多条机器指令。对于现代的抢占式操作系统,操作系统可能会在写操作的各个操作之间切换到另一个线程

这在多处理器机器上更是一个问题,多个线程可能同时执行,并试图同时写入单个内存位置


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

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

因此,如果“i”是int,这些调用(单独进行)不需要围绕“i”进行联锁交换:

a = i;
i = 9;
i = a;
i = a + 9;
a = i + 9;
if(0 == i)
a = i++;  //a = InterlockedExchange(&i, i + 1);
这些陈述都不依赖于“i”的初始值和最终值。但以下调用确实需要围绕“i”进行联锁交换:

a = i;
i = 9;
i = a;
i = a + 9;
a = i + 9;
if(0 == i)
a = i++;  //a = InterlockedExchange(&i, i + 1);
如果没有它,运行相同代码的两个线程可能会获得分配给“a”的相同“i”值,或者“a”可能会意外跳过两个或多个数字

if(0 == i++) //if(0 == InterlockedExchange(&i, i + 1))
两个线程都可以执行只发生一次的代码。

等等。

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

鉴于以上一半的答案,我也不确定答案,但我认为它是这样工作的,我可能是错的,如果我是:

  • 32位读写是原子的,但根据您的代码,这可能并不意味着什么
  • 不要担心不一致的读/写。对32位变量的所有32位写入必须对齐,否则机器页面会出现错误
  • 不要担心在缓存页面的末尾进行写包装,这是不可能发生的
  • 如果您需要在一个线程上写然后读,而您在另一个线程上写,那么您需要使用InterlockedExchange。如果您只是在一个线程上读取值,然后在另一个线程上写入值,那么您不需要使用它,但是由于多线程处理,这些值可能会摆动

  • 从运行在处理器上的软件的角度来看,它是原子的,而不是从总线上的硬件的角度来看。从运行在另一个核心上的软件的角度来看,它是原子的吗?如果写操作跨越页面边界并触发错误,该怎么办?我已经多年没有做过任何低级x86编码了,我想我可能在撒谎:/在这种情况下,我会使用InterlocatedCompareeExchange,因为检查值是否仍然是原始值已经由该方法完成了。如果会有一些中断,那么-它将花费稍长的时间,但eax中的值不会改变。联锁交换的真正意义在于它是原子读写的,然后呢?地狱。中断可能导致系统调用,系统调用上下文开关,然后另一个线程更改该值。然后,将恢复EAX并再次更改该值。计数引用时,竞争条件尤其致命。某些线程可能会增加该值,而另一个线程会减少该值,或者两个线程可能会同时增加该值。EAX恢复不是解决方案,而是问题所在。如果有多个CPU/内核,情况会变得更糟。这种情况并不严重
    b
    将使用一条指令写入,而不管它以前的值如何。缓存在这里是次要的。即使没有缓存,CPU直接与内存通信,正常的读/写顺序也不是原子的。在x86上,32位变量不需要对齐。32位写入在x86上是原子的,但在许多其他体系结构上不是原子的。-1,不正确的纯对齐写入在x86上是原子的。不正确的示例
    a=InterlockedExchange(&i,i+1)。您的
    i
    可能会被其他人更改