2012-11-15 8 views
9

Durante il porting di un codice Windows C++ su iOS, è necessario fornire un'implementazione della chiamata long InterlockedIncrement(long *p) di Win32. Questo è abbastanza facile utilizzando le funzioni definite in <libkern/OSAtomic.h>.Come implementare un incremento atomico di un puntatore su un numero intero utilizzando C++ 11 <atomic>?

Tuttavia, mi chiedo se sia possibile scriverlo in modo indipendente dall'OS utilizzando semplicemente la funzione C++ 11, principalmente <atomic>. Sono arrivato con questo, che non sono sicuro realizza ciò che voglio:

inline long InterlockedIncrement(long* p) 
{ 
    std::atomic<long&> atomicP(*p); 
    return ++atomicP; 
} 

Funziona? È abbastanza buono? Le due linee non sono atomiche, ma l'incremento dovrebbe essere atomico, che è la chiave qui.

Tutti gli esempi di utilizzo per <atomic> che ho trovato sono diversi, in cui uno std::atomic<T> è definito e utilizzato direttamente. Qui voglio utilizzare una variabile lunga esistente che i chiamanti mi passano per indirizzo. Non sono riuscito a trovare un simile esempio.

Modifica: Clang 3.2 (in Xcode 4.x) non riesce a compilare ++atomicP con l'errore "non è possibile incrementare il valore di tipo std::atomic<long&>" (né atomicP += 1).

Quale sarebbe il modo corretto?

Edit di nuovo: un'implementazione puntatore compila ...

inline long InterlockedIncrement(long* p) 
{ 
    std::atomic<long*> atomicP(p); 
    return ++(*atomicP); 
} 

ma ho paura che questo non funziona, dal momento che non incrementare un tipo atomico, ma il valore puntato dal puntatore, che non è atomico.

+0

Non penso che si possa avere un 'atomico '. E la versione del puntatore è sbagliata (il puntatore memorizzato stesso sarà atomico, non il valore puntato). – interjay

+0

No, questo non funzionerà affatto senza cose specifiche dell'implementazione. –

+2

Forse è il momento di convertirlo in 'std :: atomic ' per la porta? Considerando che 'long' ha dimensioni diverse su Windows e OSX, probabilmente dovrai comunque fare qualcosa di specifico per il sistema operativo. –

risposta

10

L'implementazione di esempio sta costruendo un nuovo atomico da un puntatore ogni volta. Questo non è l'uso previsto di std :: atomic e non credo che funzioni come vorresti.

Per quanto ne so, l'unico modo per fare ciò che si sta cercando di fare (rimuovere la dipendenza da InterlockedIncrement in modo indipendente dalla piattaforma) è quello di sostituire tutte le dichiarazioni per le variabili che si stanno attualmente chiamando chiamate "interlock" Win32 con std :: versioni atomiche di loro. Quindi, è possibile rimuovere le chiamate interbloccate e utilizzare la semantica del valore normale per modificare la variabile atomicamente. Questo è più leggibile (e più gestibile in futuro), comunque.

Capisco che desideri lasciare il codice esistente (ben collaudato) sul posto ma non credo che tu possa nel tuo caso.

+2

Avevo paura di quello. Hai riassunto la mia situazione correttamente. Grazie per la tua valutazione –

1

Credo che si possa utilizzare un'operazione atomic_fetch_add. Dai un'occhiata all'esempio here.

+2

Ciò richiede una variabile 'std :: atomic' esistente. –

+0

Poiché sta eseguendo il porting del codice da Windows, potrebbe prendere in considerazione questo e introdurre variabili atomiche (long -> std :: atomic) – Robertas

+1

Certo che potrebbe, ma non è questa la domanda che sta ponendo. La domanda dice specificamente che vuole essere passato 'long *' invece di 'std :: atomic '. – interjay

1

__atomic_add_fetch GCC estensione

Nel GCC 4.8, libreria standard C++ implementa std::atomic::operator++ con il CCG incorporato __atomic_add_fetch, così si potrebbe scrivere:

inline long InterlockedIncrement(long* p) 
{ 
    return __atomic_add_fetch(p, 1, __ATOMIC_SEQ_CST); 
} 

Non sono sicuro per clang, ma ci sembrano essere alcune opzioni come __c11_atomic_fetch_addhttp://clang.llvm.org/docs/LanguageExtensions.html

Come già menzionato, l'argomento p dovrebbe essere std::atomic per poter utilizzare solo i metodi di libreria standard: la conversione del puntatore in atomico non è di aiuto perché il puntatore atomico agisce solo sul puntatore, non su ciò a cui punta.

+0

Si noti inoltre che il GCC integrato potrebbe non essere disponibile in clang. – caps

+0

@caps In quali condizioni sono disponibili? versione clang, build-options, ecc. –

+0

Nel mio caso con Clang 3.7.0 su un CentOS 6 usando 'std = C++ 14' e usando l'implementazione della libreria standard di gcc. Quest'ultimo è probabilmente il bit chiave, dal momento che immagino che sia da dove viene estratto '__atomic_add_fetch'. Il mio IDE (che gira su OSX) non riconosce la funzione. – caps