Der folgende Codeausschnitt zeigt „lokal scoped statisches Objekt Initialisierung“ist nicht Thread-sicher:
#include <windows.h>
#include <stdio.h>
#include <process.h>
struct X {
~X() { puts("~X()"); }
int i_ ;
void print(void) {
printf("thread id=%u, i = %d\n", GetCurrentThreadId(), i_);
}
X(int i) {
puts("begin to sleep 10 seconds");
Sleep(1000 * 10);
i_ = i;
printf("X(int) i = %d\n", i_);
puts("end");
}
};
X & getX()
{
static X static_x(1000);
return static_x;
}
void thread_proc(void *)
{
X & x = getX();
x.print();
}
int main(int argc, char *argv[])
{
HANDLE all_threads[2] = {};
all_threads[0] = HANDLE(_beginthread(thread_proc, 0, 0));
printf("First thread Id: %u\n", GetThreadId(all_threads[0]));
Sleep(1000);
all_threads[1] = HANDLE(_beginthread(thread_proc, 0, 0));
printf("Second thread Id: %u\n", GetThreadId(all_threads[1]));
WaitForMultipleObjects(_countof(all_threads), all_threads, TRUE, 1000 * 20);
puts("main exit");
return 0;
}
der Ausgang (natürlich Thread-ID wird auf Ihrem Computer unterschiedlich sein) sein wird:
First thread Id: 20104
begin to sleep 10 seconds
Second thread Id: 20248
thread id=20248, i = 0
X(int) i = 4247392
end
thread id=20104, i = 1000
main exit
~X()
vor dem ersten Thread kehren die die Singletons Ctor Mittel genannt wird und zurückgeführt, wobei der zweite Thread das nicht initialisierten Objekt erhalten, und nennt es Mitglied Methode (da das statische Objekt in BSS-Segment ist, wird es sein, initilized auf Null nach Lader der ausführbaren Datei laden) und den falschen Wert erhalten: 0.
Montag durch die Auflistung Ein-/fasc /Fastatic.asm den Assembler-Code für die Funktion getX() erhalten:
01: [email protected]@[email protected]@XZ PROC ; getX
02:
03: ; 20 : {
04:
05: 00000 55 push ebp
06: 00001 8b ec mov ebp, esp
07:
08: ; 21 : static X static_x(1000);
09:
10: 00003 a1 00 00 00 00 mov eax, DWORD PTR [email protected][email protected]@[email protected]@[email protected]
11: 00008 83 e0 01 and eax, 1
12: 0000b 75 2b jne SHORT [email protected]
13: 0000d 8b 0d 00 00 00
14: 00 mov ecx, DWORD PTR [email protected][email protected]@[email protected]@[email protected]
15: 00013 83 c9 01 or ecx, 1
16: 00016 89 0d 00 00 00
17: 00 mov DWORD PTR [email protected][email protected]@[email protected]@[email protected], ecx
18: 0001c 68 e8 03 00 00 push 1000 ; 000003e8H
19: 00021 b9 00 00 00 00 mov ecx, OFFSET [email protected][email protected]@[email protected]@[email protected]@A
20: 00026 e8 00 00 00 00 call [email protected]@[email protected]@Z ; X::X
21: 0002b 68 00 00 00 00 push OFFSET [email protected][email protected]@[email protected]@[email protected] ; `getX'::`2'::`dynamic atexit destructor for 'static_x''
22: 00030 e8 00 00 00 00 call _atexit
23: 00035 83 c4 04 add esp, 4
24: [email protected]:
25:
26: ; 22 : return static_x;
27:
28: 00038 b8 00 00 00 00 mov eax, OFFSET [email protected][email protected]@[email protected]@[email protected]@A
29:
30: ; 23 : }
In Zeile 10 wird das kryptische Symbol [? $ S1 @? 1 ?? getX @@ YAAAUX @@ XZ @ 4IA] ist der globale Indikator (auch in BSS), der anzeigt, ob der Singleton corted ist oder nicht, er wird als wahr gewertet durch Zeile 14-17, kurz bevor er in den ctor ruft, das ist das Problem, das auch erklärt, warum der zweite Thread sofort das nicht initialisierte Singleton-Objekt erhalten hat und es glücklich als Member-Funktion bezeichnet. Es gibt keinen threadsicherheitsbezogenen Code, der vom Compiler eingefügt wurde.
Siehe http: // stackoverflow.com/questions/164496/how-can-ich-create-a-thread-safe-singleton-muster-in-windows – MerickOWA
@MerickOWA: Dies stammt aus dem Jahr 08 und bietet keine klare und weltweit akzeptierte Antwort. Außerdem deckt es VC2010 nicht ab (aufgrund des Themenalters). –
@ IC3M4N VS2010 wurde implementiert, bevor C++ 11 herauskam. Wenn es keine threadsichere Konstruktion von statischen lokalen Variablen implementiert, dann bleibt die Verwendung von Techniken übrig, die es schon seit vielen Jahren gibt. Ich sehe nichts, was nicht auf VS2010 – MerickOWA