代码之家  ›  专栏  ›  技术社区  ›  EFrank

何时应使用win32 interlockedexchange函数?

  •  19
  • EFrank  · 技术社区  · 16 年前

    我遇到了这个功能 InterlockedExchange 我想知道什么时候应该使用这个函数。在我看来,在x86处理器上设置32位的值应该总是原子的?
    在我要使用函数的情况下,新值不依赖于旧值(它不是增量操作)。 你能提供一个例子说明这个方法是强制的吗(我不想寻找联锁的CompareExchange)

    7 回复  |  直到 11 年前
        1
  •  4
  •   Nir    16 年前

    在多处理器或多核机器中,每个核心都有自己的缓存,因此每个核心都有自己潜在的不同“视图”,以了解系统内存的内容。

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

        2
  •  11
  •   moonshadow    16 年前

    除了写下新的价值, InterlockedExchange 同时读取并返回前一个值;整个操作是原子操作。这对 lock-free algorithms .

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

        3
  •  10
  •   Jason Cohen    16 年前

    InterlockedExchange 都是写 读——返回前一个值。

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

        4
  •  3
  •   Gerald    16 年前

    设置一个32位的值是原子的,但前提是要设置一个文本。

    B=A为2个操作:

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

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

        5
  •  3
  •   Mathieu Garstecki    16 年前

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

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

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

        6
  •  2
  •   helmk    13 年前

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

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

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

    这些语句都不依赖于“i”的初始值和最终值。但以下调用确实需要围绕“i”进行互锁交换:

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

    如果没有它,通过同一代码运行的两个线程可能会得到分配给“a”或“a”的相同值“i”,这可能会意外地跳过两个或更多的数字。

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

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

        7
  •  -1
  •   Ericf.    11 年前

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

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

    1. 32位读写是原子的,但根据代码的不同,这可能不太重要。
    2. 不要担心不对齐的读/写。对32位变量的所有32位写入都必须对齐,或者机器页面出现故障。
    3. 不要担心缓存页面末尾的写包装,这是不可能的。
    4. 如果你需要写,然后在一个线程上读,而你在另一个线程上写,那么你需要使用interlockedexchange。如果您只是在一个线程上读取值,然后在另一个线程上写入值,那么您不需要使用它,但是这些值可能会因为多线程而波动。