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]来查找此信息.