Haskell: Comment fonctionne 'atomicModifyIORef'?

quelqu'un Peut m'expliquer comment atomicModifyIORef fonctionne? Notamment:

(1) est-ce qu'il attend une serrure, ou essayez de façon optimiste et réessayez s'il y a une querelle (comme TVar).

(2) Pourquoi la signature de atomicModifyIORef différent de la signature de modifyIORef? En particulier, quelle est cette variable supplémentaire

2 ответов

atomicModifyIORef prend un r :: IORef a et une fonction f :: a -> (a, b) et effectue les opérations suivantes:

Il lit la valeur de r et s'applique f à cette valeur, donnant (a',b). Puis l' r est mis à jour avec la nouvelle valeur a'b est la valeur de retour. Cet accès en lecture et en écriture se fait atomiquement.

bien sûr, ce atomicité ne fonctionne que si accès r sont faites via atomicModifyIORef. Notez que vous pouvez trouver ces informations par en regardant la source [1].

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

10
répondu Peter 2012-04-11 13:21:20
la source

Est-ce qu'il attend une serrure, ou essayez de façon optimiste et réessayez s'il y a une querelle (comme TVar).

atomicModifyIORef utilise une instruction de verrouillage sur l'architecture matérielle sous-jacente sur laquelle vous êtes, pour échanger le pointeur vers un objet Haskell alloué de façon atomique.

sur x86 il utilise la construction cas, exposée comme une primitive au langage via atomicModifyMutVar#, qui est implémenté comme un service runtime en Cmm comme:

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
...
}

Que est, il va essayer de faire le swap, et réessayer autrement.

La mise en œuvre des tas comme un primitif, nous montre comment l'obtenir vers le bas pour le métal:

/*
 * 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;

de Sorte que vous pouvez voir qu'il est capable d'utiliser une instruction atomique en Intel, sur d'autres architectures différents mécanismes seront utilisés. L'exécution va réessayer.

28
répondu Don Stewart 2012-04-11 16:41:29
la source