Domanda


Sto usando l'operazione atomica fornita da Sunos inu003Csys/atomic.h> , che è
void *atomic_cas_ptr(volatile void *target, void *cmp, void *newval);

Ora per rendere l'uscita, devo verificare se il vecchio valore restituito da questa funzione ed è passato dalla funzione Callee CMP sono gli stessi, se sono allora l'operazione ha esito positivo.
Ma ho certi dubbi: poiché questa funzione restituisce un puntatore vuoto al vecchio valore chiamiamolo vuoto *vecchio e sto passando vuoto *CMP, allora devo confrontare questi due vecchi e CMP, quindi come ho intenzione di confrontare questi due ? E se mentre si confrontava *vecchio è cambiato, allora quello che farò?
In sostanza, quello che voglio fare è deformare questa funzione, all'interno di un'altra funzione che prende questi tre argomenti e restituisce vero o falso, che indicano il successo o il fallimento.
riguardo a CAS, ho letto che è sbagliato chiamarlo operazione di blocco, poiché alla fine prende il blocco su hardware (blocco al bus), è giusto corretto? Ecco perché il CAS è un funzionamento costoso.

È stato utile?

Soluzione

Forse la Dichiarazione della funzione ti ha confuso. Questa funzione non restituisce un puntatore al vecchio valore (di cosa?), Ma il vecchio valore dalla memoria indicata da target (che dovrebbe davvero essere un puntatore a vuoto*, cioè void* volatile * target).

Di solito se una primitiva CAS restituisce un vecchio valore piuttosto che un bool, controlli il successo CAS con qualcosa del genere:

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
}

Quindi, quando si confronta Old_Val e Comparand, lavori con variabili locali che non cambiano contemporaneamente (mentre Global Atomic_Ptr potrebbe essere nuovamente modificato) e si confrontano i valori del puntatore senza dereferencing.

La funzione che desideri dovrebbe essere così:

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

Si noti che poiché in alcuni algoritmi il vecchio valore (quello prima delle CA) dovrebbe essere noto, è meglio avere una primitiva CAS che restituisce il vecchio valore piuttosto che un bool, in quanto puoi facilmente costruire il secondo dal primo mentre il contrario è più complesso e inefficiente (vedere il seguente codice che cerca di ottenere il vecchio valore corretto di un macOS CAS primitivo che restituisce un bool).

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

Per quanto riguarda il bus di memoria di bloccaggio CAS, dipende dall'hardware. Era vero per i vecchi processori X86, ma nei moderni sistemi X86 è diverso. Innanzitutto, non esiste un autobus centrale; È stato sostituito dall'ipertransport di AMD e dall'interconnessione QuickPath di Intel. In secondo luogo, nelle recenti generazioni della CPU le istruzioni bloccate non sono tutte serializzate (vedi Alcuni dati mostrando che le istruzioni bloccate su diversi indirizzi di memoria non interferiscono). E infine, in la definizione comunemente accettata La libertà di blocco è la garanzia del progresso a livello di sistema, non di assenza di Sincronizzazione della serializzazione.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top