Static und Thread-Safety

Programmiersprachen, APIs, Bibliotheken, Open Source Engines, Debugging, Quellcode Fehler und alles was mit praktischer Programmierung zu tun hat.
Antworten
Benutzeravatar
eXile
Establishment
Beiträge: 1136
Registriert: 28.02.2009, 13:27

Static und Thread-Safety

Beitrag 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?
Benutzeravatar
Schrompf
Moderator
Beiträge: 5163
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas
Wohnort: Dresden
Kontaktdaten:

Re: Static und Thread-Safety

Beitrag 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.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Antworten