2009-12-15 17 views
9

Lo so, lo so, il titolo del mio messaggio può sembrare provocatorio, dal momento che boost :: mutex intenzionalmente non esporre blocco/sblocco (per evitare la morte serrature).boost :: mutex/Come verificare se un mutex è bloccato

Tuttavia la documentazione di boost è piuttosto corta su questi aspetti (per non dire altro), quindi mi chiedo se qualcuno può aiutarmi nel seguente caso d'uso.

Supponiamo di avere una classe Foo, che ha:
- un distruttore che richiede un po 'di tempo per completare
- un metodo che viene chiamato da un thread distinti, ma non dovrebbe essere chiamato durante la distruzione

class Foo 
{ 
public: 

    virtual ~Foo() 
    { 
    //Time consuming operations here 
    } 


    //Method called by a timer belonging to a distinct class 
    void OnTimer() 
    { 
    //Other time consuming stuff. Should not be called during destruction ! 
    } 


}; 

ho cercato (senza successo) per implementare una versione basata su boost :: mutex

//boost::mutex implementation 
class Foo 
{ 
public: 
    Foo() 
    { 
    } 

    virtual ~Foo() 
    { 
    { 
     boost::mutex::scoped_lock lock(mDisposingMutex); 
     //Time consuming operations here 
    } 
    } 


    //Method called by a timer belonging to a distinct class 
    void OnTimer() 
    { 
    { 
     //Imaginary code here: mutex::locked() method is private !!! 
     if (! mDisposingMutex.locked()) 
     return; 
    }  
    //Other time consuming stuff. Should not be called during destruction ! 
    } 

private: 
    boost::mutex mDisposingMutex; 
}; 

Am I del tutto sbagliato? Qualcuno può dirmi come dovrebbe essere fatto con boost :: mutex?

Grazie!

+0

Perché è il vostro oggetto che viene distrutto mentre un altro thread ha ancora un puntatore ad esso? –

+0

Non rispondendo direttamente alla domanda, è possibile annullare la registrazione provocando la chiamata 'OnTimer()' come primo passo nel distruttore? Certo, una chiamata può ancora arrivare in modo asincrono "allo stesso tempo", ma non è ancora chiaro perché questo oggetto sottoposto a distruzione sia ancora un bersaglio per questi callback. – seh

+0

@Anon: d'accordo, questo è un odore di codice. Comunque sono ancora interessato alla risposta. @Seh: il tuo commento è basato sullo stesso codice odore. Tuttavia, non posso cancellarlo direttamente senza interrompere l'incapsulamento. –

risposta

5

Se impegnano a utilizzare Lockable::lock() nel corpo distruttore, si potrebbe avere la funzione OnTimer() uso Lockable::try_lock(), e procedere solo se tale funzione restituisce true. Che avrà OnTimer() messo in attesa se OnTimer() inizia per primo, ma è ancora non risolve il problema del distruttore in esecuzione, finendo e rilasciando il mutex, e quindi OnTimer() iniziando e afferrando con successo il mutex.

Tale sequenza è probabile nel regno di un comportamento indefinito, ma quella maledizione non gli impedirà di accadere. L'utilizzo di un flag di stato in aggiunta al mutex - simile a quello descritto nel mio commento sopra - potrebbe consentire di rilevare quest'ultimo caso e impedire a OnTimer() di fare qualcosa oltre la lettura della bandiera. Ad un certo punto, però, questo è solo mettere Band-Aids in cima al cerotto.

2

mutex :: try_lock()

+0

Restituisce false se sei tu a bloccare il mutex. –

4

@Seh: Sono assolutamente d'accordo che questo è un odore di codice e dovrei (e lo farò) correggere la causa principale.

Tuttavia, nella speranza di aiutare chiunque incontrasse lo stesso problema di me (cioè combattendo con il documento di potenziamento), ho cercato di implementare il tuo suggerimento. Il codice qui sotto ora compila correttamente (anche se il codice odore è ora molto forte)

#include <boost/thread/mutex.hpp> 

//boost::mutex implementation 
class Foo 
{ 
public: 
    Foo() : 
    mIsDisposing(false) 
    { 
    } 

    virtual ~Foo() 
    { 
    { 
     boost::try_mutex::scoped_try_lock lock(mDisposingMutex); 
     if (! lock.locked()) 
     { 
     //Die by horrible death, or wait before trying again... 
     } 
     else 
     { 
     mIsDisposing = true; 
     } 
     //Time consuming operations here 
    } 

    } 


    //Method called by a timer belonging to a distinct class 
    void OnTimer() 
    { 
    { 
     boost::try_mutex::scoped_try_lock lock(mDisposingMutex); 
     if (! lock.locked() || mIsDisposing) 
     { 
     return;  
     } 
    }  
    //Other time consuming stuff. Should not be called during destruction ! 
    } 

private: 
    boost::try_mutex mDisposingMutex; 
    bool mIsDisposing; 
}; 
Problemi correlati