ロックを待つか、競合が発生した場合 (TVar など) に楽観的に再試行しますか。
atomicModifyIORef は、基盤となるハードウェア アーキテクチャでロック命令を使用して、割り当てられた Haskell オブジェクトへのポインタをアトミックな方法でスワップします。
atomicModifyMutVar#
x86 では、次のように Cmm でランタイム サービスとして実装されている cas 命令を使用します。
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
...
}
つまり、スワップを実行しようとし、それ以外の場合は再試行します。
プリミティブとしての 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;
Intel ではアトミック命令を使用できることがわかりますが、他のアーキテクチャでは異なるメカニズムが使用されます。ランタイムは再試行します。