Is lokale static variable initialization thread-safe in C ++ 11?

Ik weet dat dit een vaak gestelde vraag is, maar omdat er zoveel varianten zijn, wil ik het opnieuw formuleren en hopelijk een antwoord geven dat de huidige situatie weergeeft. Zoiets als

Logger& g_logger() {
    static Logger lg;
    return lg;
}

Is de constructor van variabele lg gegarandeerd maar één keer actief?

Ik weet uit eerdere antwoorden dat dit in C ++ 03 niet het geval is; in C ++ 0x-concept wordt dit afgedwongen. Maar ik wil graag een duidelijker antwoord op

  1. Is het draadveilige initialisatiegedrag in C ++ 11-standaard (geen concept) voltooid?
  2. Als het bovenstaande ja is, zijn deze in de nieuwste releases van populaire compilers, namelijk gcc 4.7, vc 2011 en clang 3.0, correct geïmplementeerd?
179
Is het veilig in VS2013 als we ervoor zorgen dat g_logger eenmaal wordt aangeroepen vanuit main() voordat andere threads worden uitgevoerd?
toegevoegd de auteur paulm, de bron
Visual Studio 2012 Update 3 ondersteunt dit niet - ik heb het getest met een kort testprogramma en de assemblagecode bekeken.
toegevoegd de auteur Tobias Langner, de bron
Kan ik het doel van zo'n functie vragen? Welke voordelen heeft het voor een eenvoudige globale logger g_logger;
toegevoegd de auteur Chris Lutz, de bron
@balki, GCC heeft het al bijna een decennium geïmplementeerd. Clang ondersteunt het ook.
toegevoegd de auteur Jonathan Wakely, de bron
@Chris: deterministische initialisatie en vermijding van het fiasco van de statische initialiseringsopdracht. Lokale statica worden eerst geïnitialiseerd wanneer de functie de eerste keer wordt aangeroepen.
toegevoegd de auteur Xeo, de bron
Voor de tweede vraag hebben nog geen compilers dit geïmplementeerd.
toegevoegd de auteur balki, de bron
"Magische statica" komt eindelijk met VS 2015: blogs.msdn.com/b/vcblog/archive/2014/11/17/…
toegevoegd de auteur mlvljr, de bron
Bedankt Xeo, dat is de belangrijkste reden. Een aantal andere zijn: 1. Normaal gesproken gebruikt de clientcode het in een logboeksysteem als macro, zoals LOG << "uw log" ... en de macro's moeten een deterministische toegang hebben tot de logger 2. De logger is niet gemaakt als je het niet gebruikt. 3. U wilt waarschijnlijk niet dat uw client meerdere loggers maakt (er is een synchronisatieprobleem, enz ...) dus de logger heeft een privéconstructor, die alleen toegankelijk is voor vriend g_logger ()
toegevoegd de auteur Ralph Zhang, de bron
Visual Studio 2013 wordt ook niet weergegeven. Zie de rij "Magische statistiek" op msdn.microsoft.com/en-us/library/vstudio/…
toegevoegd de auteur rkjnsn, de bron

2 antwoord

Het relevante deel 6.7:

een dergelijke variabele wordt geïnitialiseerd wanneer de eerste keer de controle door de declaratie gaat; een dergelijke variabele wordt beschouwd als geïnitialiseerd bij het voltooien van de initialisatie. [...] Als de controle tegelijkertijd de aangifte invoert terwijl de variabele wordt geïnitialiseerd, wacht de gelijktijdige uitvoering op het voltooien van de initialisatie.

Dan is er een voetnoot:

De implementatie mag geen impasse veroorzaken rond de uitvoering van de initialisatie.

Dus ja, je bent veilig.

(Dit zegt natuurlijk niets over de latere toegang tot de variabele via de verwijzing.)

160
toegevoegd
Het is belangrijk om op te merken dat statische Logger lg; alleen thread-safe is als de standaardconstructor van Logger thread-safe is, dat wil zeggen dat het geen toegang heeft tot enige aanpasbare gedeelde bron intern, zeg door globale variabelen of singletons. Opgemerkt moet worden dat de standaard alleen dit garandeert: als meer dan één thread probeert om de constructor gelijktijdig uit te voeren, zal slechts één daarvan daadwerkelijk uitvoeren, de rest zal wachten voor het voltooien van de initialisatie. De norm biedt echter geen enkele garantie voor de draadveiligheid van de constructeur zelf.
toegevoegd de auteur Nawaz, de bron
@KerrekSB: Ik heb ook uitgelegd wat ik daarmee bedoelde: het heeft geen toegang tot enige aanpasbare gedeelde bron intern . Alleen omdat slechts één thread een constructor uitvoert, betekent dit niet noodzakelijk dat het threadgarage is. Als het onbeveiligde gedeelde bron wijzigt, is het niet threadafe.
toegevoegd de auteur Nawaz, de bron
@Nawaz: WHy moet de constructor thread-safe zijn? U zei zelf dat slechts één thread de constructor zal uitvoeren.
toegevoegd de auteur Kerrek SB, de bron
@Nawaz: Nou, dat is waar, maar dat is ook een complete algemeenheid: gelijktijdige toegang tot gedeelde gegevens moet worden gesynchroniseerd. Ik denk niet dat er enige suggestie is dat statische initialisatie op de een of andere manier zou zorgen voor een vrijstelling van die regel, dus ik vond het niet de moeite waard om specifiek te bellen.
toegevoegd de auteur Kerrek SB, de bron
Het lijkt een beetje jammer dat noch deze vraag noch het antwoord de uitdrukking "Meyers Singleton"
toegevoegd de auteur Nemo, de bron
Het zegt ook niets over lezers van de variabele, wat betekent dat je TSAN-problemen kunt hebben als je lezers hebt die niet zijn voorafgegaan door de statische constructor. Natuurlijk, als u het bovenstaande patroon gebruikt (foo & GetFooLog() {static foo bar; return bar;}, dan doet zich het TSAN-probleem niet voor.
toegevoegd de auteur jesup, de bron
toegevoegd de auteur Ion Todirel, de bron

- fno-threadsafe-statics ook het vermelden waard. In gcc:

Straal de extra code niet uit om de routines te gebruiken die zijn opgegeven in de C ++ ABI voor draadveilige initialisatie van lokale statica. U kunt deze optie gebruiken om de codegrootte enigszins te verminderen in code die niet draadveilig hoeft te zijn.

Also, have a look at the old thread Are function static variables thread-safe in GCC?

9
toegevoegd