Question


j'utilise l'opération atomique fournie par SunOs dans , qui est
void *atomic_cas_ptr(volatile void *target, void *cmp, void *newval);

maintenant pour faire est utilisable, je dois vérifier si l'ancienne valeur retournée par cette fonction et passée par la fonction appelée cmp sont les mêmes, si elles le sont alors l'opération est réussie.
mais j'ai un doute certain: comme cette fonction renvoie un pointeur void vers l'ancienne valeur, appelons-le void * old et je passe void * cmp, alors je dois comparer ces deux anciens et cmp, alors comment je vais comparerces deux ?et si en comparant * old a changé alors qu'est-ce que je vais faire?
en essence, ce que je veux faire est de déformer cette fonction, à l'intérieur d'une autre fonction qui prend ces trois arguments et renvoie soit vrai ou faux, ce qui indique le succès ou l'échec.
à propos du CAS, j'ai lu qu'il était inapproprié de l'appeler opération sans verrouillage, car il faut finalement verrouiller le matériel (verrouiller le bus), c'est vrai?c'est pourquoi le CAS est une opération coûteuse.

Était-ce utile?

La solution

Peut-être que la déclaration de fonction vous a confondu. Cette fonction ne renvoie pas de pointeur vers l'ancienne valeur (de quoi?), Mais l'ancienne valeur de la mémoire pointée par target (qui devrait vraiment être un pointeur vers void *, c'est-à-dire void* volatile * target).

Habituellement, si une primitive CAS renvoie une ancienne valeur plutôt qu'un booléen, vous vérifiez le succès de CAS avec quelque chose comme ceci:

void* atomic_ptr; // global atomically modified pointer

void* oldval, newval, comparand; // local variables
/* ... */
oldval = atomic_cas_ptr( (void*)&atomic_ptr, /* note that address is taken */
                          comparand, newval );
if( oldval == comparand ) {
    // success
} else {
    // failure
}

Ainsi, lorsque vous comparez old_val et comparand, vous travaillez avec des variables locales qui ne changent pas simultanément (alors que global atomic_ptr peut être modifié à nouveau), et vous comparez les valeurs de pointeur sans déréférencer.

La fonction que vous voulez devrait être comme ceci:

bool my_atomic_cas_ptr(volatile void* target, void* comparand, void* newval)
{
    return (comparand == atomic_cas_ptr(target, comparand, newval));
}

Notez que puisque dans certains algorithmes l'ancienne valeur (celle avant CAS) doit être connue, il est préférable d'avoir une primitive CAS renvoyant l'ancienne valeur plutôt qu'un bool, car vous pouvez facilement construire la dernière à partir de la première tandis que le l'opposé est plus complexe et inefficace (voir le code suivant qui tente d'obtenir l'ancienne valeur correcte à partir de une primitive MacOS CAS qui renvoie un booléen).

void* CAS(void* volatile* target, void* comparand, void* newval)
{
    while( !OSAtomicCompareAndSwapPtr(comparand, newval, target) ) {
        void* snapshot = *target;
        if( snapshot!=comparand ) return snapshot;
    }
    return comparand;
}

Quant au bus mémoire de verrouillage CAS, cela dépend du matériel. C'était vrai pour les anciens processeurs x86, mais dans les systèmes x86 modernes, c'est différent. Premièrement, il n'y a pas de bus central; il a été remplacé par HyperTransport d'AMD et QuickPath Interconnect d'Intel. Deuxièmement, dans les dernières générations de CPU, les instructions verrouillées ne sont pas toutes sérialisées (voir certains données montrant que les instructions verrouillées sur différentes adresses mémoire n'interfèrent pas). Et enfin, dans la définition communément acceptée , la liberté de verrouillage est la garantie du système -nouveau progrès, pas l'absence de sérialisation de la synchronisation .

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top