Seite 1 von 1

Static und Thread-Safety

Verfasst: 13.11.2012, 15:30
von eXile
Wie ihr sicherlich wisst, vertragen sich static und mehrere Threads nicht miteinander. Genauer: Wenn eine Funktion Block-lokale static Variablen initialisiert, und mehrere Threads diese Funktion parallel ausführen können, kann undefiniertes Verhalten auftreten.

Die Standard-Antworten darauf lauten:
  1. Kopf in den Sand stecken und die Problematik ignorieren. (So nicht! So ganz sicherlich nicht!)
  2. Sich nen std::lock_guard zu schnappen und sich die Thread-Safety selber basteln.
Ein kurzer Blick in den Standard offenbart jedoch, dass diese Sorgen gänzlich unbegründet sind:
Sektion 6.7 Abs. 4 von http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf hat geschrieben:If control enters the declaration concurrently while the variable is being initialized, the concurrent execution shall wait for completion of the initialization.
D.h. mit C++11 sollte es keine Probleme mehr geben. Sollte.

Visual C++ 2010 implemententiert das schon einmal nicht. Mit Visual C++ 2012 (Vanilla) geht das auch nicht und mit dem November CTP auch nicht. Code:

Code: Alles auswählen

// Für /Wall
#pragma warning(disable : 4350 4514 4571 4625 4626 4710 4711 4820)

#include <future>
#include <iostream>

int calculate(int a, int b)
{
	static int result = 2*a + b;

	return result;
}

int main(int argc, char * argv[])
{
	int a, b;
	std::cin >> a >> b;

	std::future<int> r1 = std::async(calculate, a, b);
	std::future<int> r2 = std::async(calculate, a, b);

	std::cout << r1.get() << " " << r2.get();

	return 0;
}
Und calculate kompiliert zu:

Code: Alles auswählen

int calculate(int a, int b)
{
00C71ED0  push        ebp  
00C71ED1  mov         ebp,esp  
	static int result = 2*a + b;
00C71ED3  mov         eax,dword ptr ds:[00C79E60h]  
00C71ED8  test        al,1  
00C71EDA  jne         calculate+24h (0C71EF4h)  
00C71EDC  mov         ecx,dword ptr [ b]  
00C71EDF  or          eax,1  
00C71EE2  mov         dword ptr ds:[00C79E60h],eax  
00C71EE7  mov         eax,dword ptr [a]  
00C71EEA  lea         eax,[ecx+eax*2]  
00C71EED  mov         dword ptr ds:[00C79E58h],eax  
}
00C71EF2  pop         ebp  
00C71EF3  ret  

	return result;
00C71EF4  mov         eax,dword ptr ds:[00C79E58h]  
}
00C71EF9  pop         ebp  
00C71EFA  ret  
Ich sehe da zumindest nichts von den Garantien des Standards. Visual Studio 2012 CTP sagt mir sogar rotzfrech auf /Wall:

1>C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\include\thr/xthread(172): warning C4265: 'std::_Pad' : class has virtual functions, but destructor is not virtual
1> instances of this class may not be destructed correctly
1>main.cpp(10): warning C4640: 'result' : construction of local static object is not thread-safe
1>main.cpp(15): warning C4100: 'argv' : unreferenced formal parameter
1>main.cpp(15): warning C4100: 'argc' : unreferenced formal parameter


Ich hoffe, dass ich jetzt keinen Mist gebaut habe. Was sagt ihr dazu?

Re: Static und Thread-Safety

Verfasst: 13.11.2012, 15:33
von Schrompf
Interessant zu wissen. Anscheinend wird diese Änderung am Standard von VS2012 noch nicht umgesetzt. Ich dachte ja bisher, dass wäre ne ganz einfache Sache mit std::atomic_bool... oder stell ich mir das zu einfach vor? Die atomaren Typen müssten doch in Hardware umgesetzt und nahezu kostenlos sein.