Visual Studio 2012 non implementa lo standard C++ 11 per l'inizializzazione statica thread-safe (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2660.htm). Ho una funzione locale statica che devo garantire che verrà inizializzata in modo thread-safe. Di seguito è non thread-safe in Visual Studio 2012:Il thread di inizializzazione statica std :: atomic_flag è sicuro in Visual Studio 2012?
struct MyClass
{
int a;
MyClass()
{
std::this_thread::sleep_for(std::chrono::milliseconds(100));
a = 5;
}
};
void foo()
{
static MyClass instance;
std::cout << instance.a << '\n';
}
int main()
{
std::thread a(foo);
std::thread b(foo);
a.join();
b.join();
system("pause");
}
L'uscita del programma di cui sopra su Visual Studio 2012 sarà molto probabilmente:
0
5
ho bisogno di lavorare intorno a questo problema e sto cercando di trovare un modo per farlo solo con la funzione statica locale (nessuna statistica globale o di livello di classe).
Il mio primo pensiero era di usare un mutex, ma soffre dello stesso problema di sicurezza del thread di inizializzazione statica. Se ho uno static st :: mutex all'interno di foo è possibile che il secondo thread ottenga una copia del mutex mentre si trova in uno stato non valido.
Un'altra opzione è aggiungere uno spin-lock std :: atomic_flag. La domanda è, è std :: atomic_flag thread di inizializzazione sicuro in Visual Studio 2012?
void foo()
{
// is this line thread safe?
static std::atomic_flag lock = ATOMIC_FLAG_INIT;
// spin lock before static construction
while (lock.test_and_set(std::memory_order_acquire));
// construct an instance of MyClass only once
static MyClass instance;
// end spin lock
lock.clear(std::memory_order_release);
// the following is not thread safe
std::cout << instance.a << '\n';
}
Nel codice precedente, è possibile per entrambi i fili di superare la spin lock o è garantito che solo uno di essi? Sfortunatamente non riesco a pensare a un modo semplice per testarlo poiché non posso mettere qualcosa dentro l'inizializzatore atomic_flag per rallentarlo come faccio con una classe. Tuttavia, voglio essere sicuro che il mio programma non si bloccherà una volta in una luna blu perché ho fatto un'ipotesi non valida.
Sono confuso da questo stesso problema. Dato che "la funzione statica locale" è la risposta classica al [fiasco statico di ordine init] (http://www.parashift.com/c++-faq/static-init-order.html), VS ci mette in una situazione molto stretta legare con questo! –
La guardia spinlock è stato il modo in cui ho risolto il problema. Assicurati di includere la roba dell'ordine di memoria, altrimenti potresti ancora avere una condizione di competizione a causa del riordino della memoria da parte del compilatore/CPU! Una volta che l'inizializzazione è stata eseguita per la prima volta, il codice sopra riportato non dovrebbe quasi mai girare poiché acquisisce e cancella il blocco in pochissimi cicli. Se si trattasse di un pezzo di codice critico per le prestazioni, probabilmente si potrebbe fare meglio con un booleano non volatile che avvolge tutto ciò che passa da falso a vero (mai vero a falso) per evitare una potenziale sincronizzazione di base. –