Domanda

Come scriveresti una funzione in C che effettui un confronto atomico e scambi su un valore intero, utilizzando il codice macchina incorporato (assumendo, ad esempio, l'architettura x86)?Può essere più specifico se è scritto solo per il processore i7?

La traduzione agisce come un recinto di memoria o garantisce semplicemente la relazione di ordinamento solo su quella posizione di memoria inclusa nel confronto e nello scambio?Quanto costa rispetto a un recinto di memoria?

Grazie.

È stato utile?

Soluzione

Il modo più semplice per farlo è probabilmente con un compilatore intrinseca come _InterlockedCompareExchange () . Sembra una funzione, ma è in realtà un caso speciale nel compilatore che si riduce a una sola op macchina. Nel caso del MSVC x86 intrinseca, che funziona come un recinto di lettura / scrittura pure, ma questo non è necessariamente vero su altre piattaforme. (Per esempio, il PowerPC, avresti bisogno di rilasciare in modo esplicito un lwsync al riordino della memoria recinzione.)

In generale, su molti sistemi comuni, un'operazione di confronto-e-swap di solito impone solo una transazione atomica sulla indirizzo uno è toccante. Altro accesso memoria può essere riordinato, e in multicore sistemi, gli indirizzi di memoria diversi da quello che hai scambiato potrebbe non essere coerente tra i nuclei.

Altri suggerimenti

È possibile utilizzare l'istruzione CMPXCHG con il prefisso LOCK per l'esecuzione atomica.

per es.

lock cmpxchg DWORD PTR [ebx], edx

o

lock cmpxchgl %edx, (%ebx)

Questa confronta il valore nel registro EAX con il valore all'indirizzo memorizzato nel registro EBX e memorizza il valore nel registro EDX in quella posizione se sono lo stesso, altrimenti si carica il valore all'indirizzo memorizzato nel EBX registrare in EAX.

È necessario disporre di un 486 o successivo per questa istruzione sia disponibile.

Se il valore intero è a 64 bit di uso CMPXCHG8B 8 byte confronto e lo scambio sotto IA32 x86. Variabile deve essere di 8 byte allineato.

Example:
      mov   eax, OldDataA           //load Old first 32 bits
      mov   edx, OldDataB           //load Old second 32 bits
      mov   ebx, NewDataA           //load first 32 bits
      mov   ecx, NewDataB           //load second 32 bits
      mov   edi, Destination        //load destination pointer
      lock cmpxchg8b qword ptr [edi]
      setz  al                      //if transfer is succesful the al is 1 else 0

Se il prefisso LOCK viene omesso nelle istruzioni del processore atomico, lo farà il funzionamento atomico in un ambiente multiprocessore non essere garantito.

In un ambiente multiprocessore, il segnale LOCK# garantisce che il processore abbia l'uso esclusivo di qualsiasi memoria condivisa mentre il segnale viene affermato. Riferimento al set di istruzioni Intel

Senza il prefisso LOCK l'operazione garantirà di non essere interrotta da alcun evento (interrupt) solo sul processore/core corrente.

E 'interessante notare che alcuni processori non forniscono un confronto-scambio, ma invece forniscono alcune altre istruzioni ( "Load Linked" e "condizionale STORE") che possono essere utilizzati per sintetizzare il purtroppo nome compare-e- swap (i suoni nome come dovrebbe essere simile a "confronto-scambio", ma in realtà dovrebbe essere chiamato "confrontare-e-store", in quanto si fa il confronto, i negozi se le partite di valore, e indica se il valore abbinato e il negozio era eseguita). Le istruzioni non può sintetizzare la semantica di confronto-scambio (che fornisce il valore che è stato letto nel caso in cui il confrontare fallito), ma in alcuni casi possono evitare il problema ABA, che è presente con confronto-scambio. Molti algoritmi sono descritti in termini di operazioni di "CAS" perché possono essere utilizzati su entrambi gli stili di CPU.

A "Load Linked" istruzione dice al processore di leggere una locazione di memoria e l'orologio in qualche modo per vedere se potrebbe essere scritta. Un'istruzione "condizionale Store" indica al processore di scrivere una posizione di memoria solo se nulla può averlo scritto dopo l'ultimo "Load Linked" operazione. Si noti che la determinazione può essere pessimisti; elaborazione di un interrupt, per esempio, può invalidare una / sequenza "Load-Linked" "condizionale Store". Analogamente in un sistema multi-processore, una sequenza LL / CS può essere invalidata da un'altra CPU accedendo ad una posizione sulla stessa linea di cache come posizione di essere osservato, anche se la posizione attuale osservata non è stata toccata. Nell'uso tipico, LL / CS sono usati molto vicini tra loro, con un ciclo di tentativi, in modo che invalidazione errate possono rallentare le cose un po 'ma non sarà causa molti problemi.

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