2012-11-09 13 views
6

Capisco il concetto di sicurezza del filo. Sto cercando un consiglio per semplificare la sicurezza del thread quando si cerca di proteggere una singola variabile.Sicurezza filettatura di una singola variabile

Dire che ho una variabile:

double aPass; 

e voglio proteggere questa variabile, così ho creare un mutex:

pthread_mutex_t aPass_lock; 

Ora ci sono due maniere buone mi viene in mente di fare questo ma entrambi hanno fastidiosi svantaggi. Il primo è quello di fare una classe thread-safe per contenere la variabile:

class aPass { 
    public: 
     aPass() { 
      pthread_mutex_init(&aPass_lock, NULL); 
      aPass_ = 0; 
     } 

     void get(double & setMe) { 
      pthread_mutex_lock(aPass_lock); 
      setMe = aPass_ 
      pthread_mutex_unlock(aPass_lock); 
     } 

     void set(const double setThis) { 
      pthread_mutex_lock(aPass_lock); 
      aPass_ = setThis; 
      pthread_mutex_unlock(aPass_lock); 
     } 
    private: 
     double aPass_; 
     pthread_mutex_t aPass_lock; 
}; 

Ora Ciò manterrà aPass totalmente sicuro, nulla può essere sbagliata e mai toccarlo, YAY! tuttavia guarda tutto quel casino e immagina la confusione quando accedici. schifoso.

L'altro modo è averli entrambi accessibili e assicurarsi di bloccare il mutex prima di utilizzare aPass.

Ma se qualcuno entra nel progetto, se si dimentica una volta per bloccarlo. Non mi piace il debug dei problemi con i thread, sono difficili.

C'è un buon modo per (usare pthreads perché devo usare QNX che ha un piccolo supporto boost) Per bloccare singole variabili senza bisogno di una grande classe e che è più sicuro, basta creare un mutex lock per andare con esso?

+0

questa variabile è una variabile globale? Non penso che tu abbia molta altra scelta ... a meno che tu non voglia fare una classe contenitore generica thread-safe - questo ti farebbe risparmiare un po 'di codice se dovessi fare una seconda var. –

+0

intendi come classe di un modello? sembra abbastanza buono. –

+0

inoltre, non è possibile da ur design duplicare il var? apass è una classe così posso avere tanti oggetti quanti voglio –

risposta

3

Per elaborare la mia soluzione, sarebbe qualcosa di simile.

template <typename ThreadSafeDataType> 
class ThreadSafeData{ 
    //.... 
private: 
    ThreadSafeDataType data; 
    mutex mut; 
}; 

class apass:public ThreadSafeData<int> 

Inoltre, per renderlo unico, potrebbe essere opportuno rendere statici tutti gli operatori ei membri. Per farlo funzionare è necessario utilizzare CRTP cioè

template <typename ThreadSafeDataType,class DerivedDataClass> 
class ThreadSafeData{ 
//.... 
}; 
class apass:public ThreadSafeData<int,apass> 
+1

Benvenuti in SO! Per favore non usare txt-speak nella tua comunicazione, non è necessario qui ed è generalmente disapprovato. – GManNickG

1

È possibile creare una classe che funge da wrapper generico attorno alla variabile che sincronizza l'accesso ad essa.

Aggiungere l'overloading dell'operatore per l'assegnazione e il gioco è fatto.

+0

Qualche esempio di codice? Significa anche avere ognuno dei tipi di variabile che intendo utilizzare in una classe con ogni funzione sovraccaricata per quel tipo. Sembra piuttosto disordinato. –

+0

È possibile creare una classe modello che funzionerà con qualsiasi tipo di dati. – thedayofcondor

+0

Vedi @Karthik T code ... il mio C++ è un po 'arrugginito e non sarebbe in grado di scrivere la parte superiore della mia testa senza un IDE ... Sto diventando troppo vecchio – thedayofcondor

1

considerare l'uso RAII idiom, sotto il codice è solo l'idea, non è testato:

template<typename T, typename U> 
struct APassHelper : boost::noncoypable 
{ 
    APassHelper(T&v) : v_(v) { 
    pthread_mutex_lock(mutex_); 
    } 
    ~APassHelper() { 
    pthread_mutex_unlock(mutex_); 
    } 
    UpdateAPass(T t){ 
    v_ = t; 
    } 
private: 
    T& v_; 
    U& mutex_; 
}; 

double aPass; 
int baPass_lock; 
APassHelper<aPass,aPass_lock) temp; 
temp.UpdateAPass(10); 
+0

questo richiede ancora agli utenti di utilizzare manualmente l'helper, che l'OP vuole evitare –

2

Si può facilmente rendere la propria classe che blocca il mutex sulla costruzione, e lo sblocca sulla distruzione. In questo modo, indipendentemente da ciò che accade, il mutex verrà liberato al momento del ritorno, anche se viene lanciata un'eccezione o viene eseguito un percorso.

class MutexGuard 
{ 
    MutexType & m_Mutex; 
public: 

    inline MutexGuard(MutexType & mutex) 
     : m_Mutex(mutex) 
    { 
     m_Mutex.lock(); 
    }; 

    inline ~MutexGuard() 
    { 
     m_Mutex.unlock(); 
    }; 
} 


class TestClass 
{ 
    MutexType m_Mutex; 
    double m_SharedVar; 

    public: 
     TestClass() 
      : m_SharedVar(4.0) 
     { } 

     static void Function1() 
     { 
      MutexGuard scopedLock(m_Mutex); //lock the mutex 
      m_SharedVar+= 2345; 
      //mutex automatically unlocked 
     } 
     static void Function2() 
     { 
      MutexGuard scopedLock(m_Mutex); //lock the mutex 
      m_SharedVar*= 234; 
      throw std::runtime_error("Mutex automatically unlocked"); 
     } 

} 

La m_SharedVar variabile è assicurata mutua esclusione tra Function1() e Function2(), e sarà sempre sbloccato il ritorno.

boost ha creato tipi per ottenere ciò: boost :: scopeed_locked, boost :: lock_guard.

+1

Cool risposta ma purtroppo ho detto nella mia domanda non posso usare boost. Altrimenti sarei serrex mutex tutto ambito. –

+3

Lui ti ha mostrato come creare il tuo blocco con scope –

1

È possibile modificare la classe Apass utilizzando operatori, invece di get/set:

class aPass { 
public: 
    aPass() { 
     pthread_mutex_init(&aPass_lock, NULL); 
     aPass_ = 0; 
    } 

    operator double() const { 
     double setMe; 
     pthread_mutex_lock(aPass_lock); 
     setMe = aPass_; 
     pthread_mutex_unlock(aPass_lock); 
     return setMe; 
    } 

    aPass& operator = (double setThis) { 
     pthread_mutex_lock(aPass_lock); 
     aPass_ = setThis; 
     pthread_mutex_unlock(aPass_lock); 
     return *this; 
    } 
private: 
    double aPass_; 
    pthread_mutex_t aPass_lock; 
}; 

Usage:

aPass a; 
a = 0.5; 
double b = a; 

Questo potrebbe naturalmente essere templato per supportare altri tipi. Si noti tuttavia che un mutex è eccessivo in questo caso. Generalmente, le barriere di memoria sono sufficienti quando si proteggono carichi e archivi di piccoli tipi di dati. Se possibile, utilizzare C++ 11 std::atomic<double>.

5
std::atomic<double> aPass; 

fornito di C++ 11.

+0

sfortunatamente no, non ho C++ 11 –

Problemi correlati