Haskell:'atomicModifyIORef'是如何工作的?

Cli*_*ton 26 concurrency haskell locking atomicity compare-and-swap

有人可以解释一下atomicModifyIORef有效吗?特别是:

(1)是否等待锁定,或者乐观地尝试重试(如果存在争用TVar).
(2)为什么签名atomicModifyIORef不同于签名modifyIORef?特别是,这个额外的变量是什么b

编辑:我想我已经找到了(2)的答案,因为这b是一个要提取的值(如果不需要,这可以是空的).在单线程程序中,知道该值是微不足道的,但在多线程程序中,人们可能想知道在应用函数时先前的值是什么.我假设这就是为什么modifyIORef没有这个额外的返回值(因为这样的modifyIORef返回值的使用可能应该使用atomicModifyIORef.我仍然对(1)的答案感兴趣.

Don*_*art 32

是否等待锁定,或乐观地尝试重试是否存在争用(如TVar).

atomicModifyIORef在您所使用的底层硬件体系结构上使用锁定指令,以原子方式将指针交换为已分配的Haskell对象.

在x86上,它使用cas intruction,作为语言的一个原语公开,atomicModifyMutVar#在Cmm中实现为运行时服务:

stg_atomicModifyMutVarzh
{
...

 retry:
   x = StgMutVar_var(mv);
   StgThunk_payload(z,1) = x;
#ifdef THREADED_RTS
   (h) = foreign "C" cas(mv + SIZEOF_StgHeader + OFFSET_StgMutVar_var, x, y) [];
   if (h != x) { goto retry; }
#else
   StgMutVar_var(mv) = y;
#endif
...
}
Run Code Online (Sandbox Code Playgroud)

也就是说,它会尝试进行交换,否则重试.

cas作为基元的实现显示了我们如何深入到金属:

/*
 * Compare-and-swap.  Atomically does this:
 */
EXTERN_INLINE StgWord cas(StgVolatilePtr p, StgWord o, StgWord n);

/*
 * CMPXCHG - the single-word atomic compare-and-exchange instruction.  Used
 * in the STM implementation.
 */
EXTERN_INLINE StgWord
cas(StgVolatilePtr p, StgWord o, StgWord n)
{
#if i386_HOST_ARCH || x86_64_HOST_ARCH
    __asm__ __volatile__ (
      "lock\ncmpxchg %3,%1"
          :"=a"(o), "=m" (*(volatile unsigned int *)p)
          :"0" (o), "r" (n));
    return o;
#elif arm_HOST_ARCH && defined(arm_HOST_ARCH_PRE_ARMv6)
    StgWord r;
    arm_atomic_spin_lock();
    r  = *p;
    if (r == o) { *p = n; }
    arm_atomic_spin_unlock();
    return r;
#elif !defined(WITHSMP)
    StgWord result;
    result = *p;
    if (result == o) {
        *p = n;
    }
    return result;
Run Code Online (Sandbox Code Playgroud)

因此,您可以看到它能够在英特尔中使用原子指令,在其他架构上将使用不同的机制.运行时将重试.


Pet*_*ter 12

atomicModifyIORef采用a r :: IORef a和函数f :: a -> (a, b)并执行以下操作:

它读取值r并应用于f此值,产生(a',b).然后r使用新值更新,a'b返回值.这种读写访问是以原子方式完成的.

当然,这种原子性只有在通过所有访问r完成时才有效atomicModifyIORef.请注意,您可以通过查看源[1]来查找此信息.

[1] http://hackage.haskell.org/packages/archive/base/latest/doc/html/src/Data-IORef.html#atomicModifyIORef

  • 乐观,通过互锁交换(cas)循环.https://github.com/ghc/ghc/blob/45740c29b24ea78b885d3b9f737a8bdc00265f7c/rts/PrimOps.cmm#L364 (12认同)
  • 它是执行锁定还是乐观?GHC版本似乎只是称为GHC原语. (3认同)
  • 注意,由于懒惰,“ atomicModifyIORef”仅需更改当前值以指向一个thunk,实际工作便会延迟到稍后再读取。AFAIK,在大多数平台上都可以编译为类似CAS的文件。 (2认同)