2009-06-27 14 views
13

Ricordo di aver letto che le variabili statiche dichiarate all'interno metodi non è thread-safe. (Vedere What about the Meyer's singleton? come detto da Todd Gardner)variabili statiche thread-safe senza mutexing?

Dog* MyClass::BadMethod() 
{ 
    static Dog dog("Lassie"); 
    return &dog; 
} 

Biblioteca genera codice C++ per gli utenti finali a compilare come parte della loro applicazione. Il codice che genera deve inizializzare le variabili statiche in un modo cross-platform sicuro per i thread. Mi piacerebbe usare boost::call_once al mutex inizializzazione delle variabili, ma poi gli utenti finali sono esposti alla dipendenza Boost.

Esiste un modo per me di fare questo senza forzare le dipendenze in più sugli utenti finali?

+0

È anche possibile collegare in modo statico le librerie di boost in proprio, quindi è possibile utilizzare boost tutto ciò che si desidera senza timore di disturbo per gli utenti. – Ben

+0

possibile duplicato di [Inizializzazione di variabili statiche locali thread-safe in C++ 11?] (Http://stackoverflow.com/questions/8102125/is-local-static-variable-initialization-thread-safe-in-c11 –

+1

@LucianAdrianGrijincu, questa domanda è precedente a C++ 11 (è stata pubblicata nel 2009) quindi, sebbene la tua domanda sia correlata, non è un duplicato rigoroso. Grazie per il link. – Gili

risposta

10

Lei ha ragione che l'inizializzazione statica del genere non è thread-safe (here è un articolo che discute quello che il compilatore lo trasformerà in)

Al momento, non c'è alcuna norma, thread-safe, modo portabile per inizializzare singleton statici. È possibile utilizzare il doppio blocco controllato, ma sono necessarie librerie di thread potenzialmente non portatili (vedere una discussione here).

Ecco alcune opzioni se la sicurezza thread è un must:

  1. non essere pigro (caricati): inizializzare durante l'inizializzazione statica. Potrebbe essere un problema se un'altra statica chiama questa funzione nel suo costruttore, poiché l'ordine di inizializzazione statica non è definito (vedi here).
  2. Usa spinta (come ha detto lei) o Loki
  3. rotolare il proprio Singleton sulle piattaforme supportate (dovrebbe probabilmente essere evitato a meno sei un esperto di threading)
  4. Blocco di un mutex ogni volta è necessario accedere. Questo potrebbe essere molto lento.

Esempio per 1:

// in a cpp: 
namespace { 
    Dog dog("Lassie"); 
} 

Dog* MyClass::BadMethod() 
{ 
    return &dog; 
} 

Esempio per 4:

Dog* MyClass::BadMethod() 
{ 
    static scoped_ptr<Dog> pdog; 
    { 
    Lock l(Mutex); 
    if(!pdog.get()) 
     pdog.reset(new Dog("Lassie")); 
    } 
    return pdog.get(); 
} 
+0

Ho finito per mordere il proiettile e usando 'boost :: call_once()' – Gili

+7

questa risposta è ora obsoleta: http://stackoverflow.com/questions/8102125/is-local-static-variable-initialization-thread-safe- in-C11 – Yankes

2

L'unico modo che conosco per garantire che non avrete problemi di threading con risorse non protette come il vostro "static Dog" è quello di renderlo un requisito che sono tutti istanze prima sono creati qualsiasi thread.

Questo potrebbe essere semplice come documentare semplicemente che devono chiamare una funzione MyInit() nella discussione principale prima di fare qualsiasi altra cosa. Poi si costruisce MyInit() per istanziare e distruggere un oggetto di ogni tipo che contiene uno di quei statica.

L'unica altra alternativa consiste nel mettere un'altra restrizione su come possono utilizzare il codice generato (utilizzare Boost, thread Win32, ecc.). A mio parere entrambe le soluzioni sono accettabili: è corretto generare regole che devono seguire.

Se essi non seguono le regole stabilite dall'agenda la documentazione, tutte le scommesse sono spenti. La regola per cui devono chiamare una funzione di inizializzazione o dipendere da Boost non è irragionevole per me.

3

Un modo che si possa fare è che non richiede un mutex per la sicurezza filo è quello di rendere il singleton un file statico, piuttosto che funzione statica:

static Dog dog("Lassie"); 
Dog* MyClass::BadMethod() 
{ 
    return &dog; 
} 

L'istanza Dog verrà inizializzato prima che il thread principale piste. Le variabili statiche del file hanno un famoso problema con l'ordine di inizializzazione, ma finché il cane non fa affidamento su qualsiasi altra statica definita in un'altra unità di traduzione, ciò non dovrebbe essere motivo di preoccupazione.

+0

Ricordo che potrebbero esserci problemi se si hanno inizializzatori globali in DLL su Windows - ma non riesco a richiamare specifiche, ed è davvero rilevante solo se il codice è in una DLL comunque: D – olliej

+0

Il mio codice * fa * risiede in una DLL :) Di quali problemi dovrei essere a conoscenza? – Gili

+0

dannatamente se lo so. La mia ipotesi migliore è che il costruttore verrà eseguito una volta ogni volta che viene caricata la dll, quindi se la dll viene scaricata e ricaricata verrà ricreata in modo tale da rompere il "contratto" di Singleton ma non molto da fare su quello –

2

per quanto ne so, l'unica volta che questo è stato fatto in modo sicuro e senza mutex o prima inizializzazione di istanze globali è in Matteo Wilson Imperfect C++, che spiega come farlo usando un "spin mutex". Non sono vicino alla mia copia di esso, quindi non posso dirti con più precisione in questo momento.

IIRC, ci sono alcuni esempi dell'uso di questo all'interno delle librerie STLSoft, anche se non riesco a ricordare quali componenti in questo momento.

4

Non sicuro se questo è ciò che intendi o no, ma puoi rimuovere la dipendenza da boost sui sistemi POSIX chiamando invece pthread_once. Immagino che dovresti fare qualcosa di diverso su Windows, ma evitarlo è esattamente il motivo per cui boost ha una libreria di thread in primo luogo e perché la gente paga il prezzo di dipendere da esso.

Fare qualcosa "thread-safe" è intrinsecamente legato all'implementazione dei thread. Devi dipendere da qualcosa di, anche se è solo il modello di memoria dipendente dalla piattaforma. Semplicemente non è possibile in C++ 03 puro assumere qualsiasi cosa sui thread, che sono al di fuori dell'ambito del linguaggio.