Sì: Boost.Thread è ottimo, e dovrebbe soddisfare le tue esigenze molto bene. (In questi giorni, molte persone dicono che potresti quasi contare Boost come funzionalità built-in.)
Non esiste ancora una classe che potresti utilizzare immediatamente, ma una volta che hai a disposizione i primitivi di sincronizzazione , è abbastanza semplice implementare il proprio wrapper thread-safe, ad esempio, std::stack
. Potrebbe essere simile a questa (non implementare tutti i metodi ...):
template <typename T> class MyThreadSafeStack {
public:
void push(const T& item) {
boost::mutex::scoped_lock lock(m_mutex);
m_stack.push(item);
}
void pop() {
boost::mutex::scoped_lock lock(m_mutex);
m_stack.pop();
}
T top() const { // note that we shouldn't return a reference,
// because another thread might pop() this
// object in the meanwhile
boost::mutex::scoped_lock lock(m_mutex);
return m_stack.top();
}
private:
mutable boost::mutex m_mutex;
std::stack<T> m_stack;
}
Se siete nuovi a C++, si prega di conoscere RAII. Pertinente a questo caso, Boost.Thread ha le classi "scoped lock" per rendere difficile spararti a una gamba dimenticando di rilasciare un lucchetto.
Se vi trovate mai a scrivere codice come questo:
void doStuff() {
myLock.lock();
if (!condition) {
reportError();
myLock.unlock();
return;
}
try {
doStuffThatMayThrow();
}
catch (std::exception& e) {
myLock.unlock();
throw e;
}
doMoreStuff();
myLock.unlock();
}
, allora si dovrebbe solo dire no, e andare Raii invece (sintassi non direttamente da Boost):
void doStuff() {
scoped_lock lock;
if (!condition) {
reportError();
return;
}
doStuffThatMayThrow();
doMoreStuff();
}
Il punto è che quando l'oggetto scoped_lock
esce dall'ambito, il suo distruttore rilascia la risorsa, in questo caso il lucchetto. Ciò accadrà sempre, indipendentemente dal fatto che tu esca dall'oscillazione lanciando un'eccezione o eseguendo l'affermazione dispari return
che il tuo collega ha aggiunto di nascosto nel mezzo della tua funzione, o semplicemente raggiungendo la fine della funzione.
Se si è interessati all'atomicità delle istruzioni x86 PUSH/POP, si prega di fare una domanda separata - non ha nulla a che fare con C++, che non userebbe tali istruzioni per accedere a una struttura di dati dello stack. –
Il comitato è più impegnato nella scrittura di classi parallele di predicazione su DDJ piuttosto che fare astrazioni di modello di memoria atomiche e molto migliori per il compilatore obbligatorio in TR1 (probabilmente nemmeno in TR2). Per rispondere: non si fa veramente push e pop e quindi si modificano implicitamente i registri sui thread che dicono che corrono attualmente su core distinti, vero? :-) Bel colpo, ma non avrebbe funzionato .. Non puoi farlo senza bloccare o almeno senza il martello CAS. Per gli zeloti C++: dovrebbero semplicemente sedersi e definire e concordare i protocolli di coerenza esistenti, + lasciare spazio per nuovi sviluppi. –
Per gli interessati, ho esaminato le operazioni atomiche e Intel ha il supporto DCAS attraverso il cmpxchg16b. Sfortunatamente AMD ha solo cmpxchg8b. Non importa per me, dal momento che sto scrivendo per macchine Intel :) – bugmenot77