[MSVC 2013] Function local static zero-init
Verfasst: 23.09.2014, 18:35
Hallo liebe Community!
Wir haben ein interessantes C++ Problem mit scoped static variables.
Zuerst einmal: wir nutzen Visual Studio 2013 ohne November CTP (dieses macht nämlich an anderer Stelle Probleme), weswegen scoped static initialization nicht threadsafe ist.
Insbesondere ist folgender Code eine Race Condition (die uns auch tatsächlich in der Anwendung diverse non-deterministische Access Violations liefert):
(Der Code wird natürlich aus diversen Thread parallel aufgerufen)
Es wird noch schlimmer, wir haben hunderte solcher statisch-lokalen Variablen (durch ein Macro).
(Unter gcc und clang ist natürlich alles ok, die implementieren das threadsafe init von C++11 bereits korrekt)
Da nach der ersten Initialisierung kaum noch Aufwand auf diese Codestelle entfällt, kam mir die Idee, ein Spinlock zum sichern zu nehmen:
Das funktioniert zwar, benötigt aber eigentlich für jede static variable einen eigenen Lock, den ich ja wegen des Problems auch nicht als static mit in die Funktion packen kann (eigentlich).
Insbesondere ist das für unser Macro dann sehr unangenehm, außerhalb der Funktionen noch die Locks zu erstellen.
Allerdings ist ATOMIC_FLAG_INIT ein #define auf {0} und so wie die Implementierung von atomic_flag im VS 13 aussieht, müsste das astreine zero-initialization sein.
Jetzt die Frage: kann man vll doch einfach threadsafe static den lock zero-initialisieren und dann als spinlock verwenden?
Oder offener: hat jemand eine bessere Idee mit dem Problem umzugehen?
Wir haben ein interessantes C++ Problem mit scoped static variables.
Zuerst einmal: wir nutzen Visual Studio 2013 ohne November CTP (dieses macht nämlich an anderer Stelle Probleme), weswegen scoped static initialization nicht threadsafe ist.
Insbesondere ist folgender Code eine Race Condition (die uns auch tatsächlich in der Anwendung diverse non-deterministische Access Violations liefert):
(Der Code wird natürlich aus diversen Thread parallel aufgerufen)
Code: Alles auswählen
foo()
{
static A* a = bar();
... a nutzen
}
(Unter gcc und clang ist natürlich alles ok, die implementieren das threadsafe init von C++11 bereits korrekt)
Da nach der ersten Initialisierung kaum noch Aufwand auf diese Codestelle entfällt, kam mir die Idee, ein Spinlock zum sichern zu nehmen:
Code: Alles auswählen
static std::atomic_flag lock = ATOMIC_FLAG_INIT; // non-function scope
foo()
{
while (lock.test_and_set(std::memory_order_acquire)) { } // spin
static A* a = bar();
lock.clear(std::memory_order_release);
... a nutzen
}
Insbesondere ist das für unser Macro dann sehr unangenehm, außerhalb der Funktionen noch die Locks zu erstellen.
Allerdings ist ATOMIC_FLAG_INIT ein #define auf {0} und so wie die Implementierung von atomic_flag im VS 13 aussieht, müsste das astreine zero-initialization sein.
Jetzt die Frage: kann man vll doch einfach threadsafe static den lock zero-initialisieren und dann als spinlock verwenden?
Oder offener: hat jemand eine bessere Idee mit dem Problem umzugehen?