Vraag "Volatile" kwalificatie en compiler-nabestellingen


Een compiler kan lezen / schrijven naar a niet verwijderen of opnieuw rangschikken volatile-gekwalificeerde variabelen.

Maar hoe zit het met de gevallen waarin andere variabelen aanwezig zijn, die al dan niet aanwezig kunnen zijn volatile-gekwalificeerd?

Scenario 1

volatile int a;
volatile int b;

a = 1;
b = 2;
a = 3;
b = 4;

Kan de compiler eerst opnieuw ordenen en de tweede of derde en vierde opdracht?

Scenario 2

volatile int a;
int b, c;

b = 1;
a = 1;
c = b;
a = 3;

Dezelfde vraag, kan de compiler eerst opnieuw ordenen en de tweede of derde en de vierde opdracht?


13
2018-03-29 00:15


oorsprong


antwoorden:


De C ++ -standaard zegt (1.9 / 6):

Het waarneembare gedrag van de   abstracte machine is de volgorde van   leest en schrijft naar vluchtige gegevens en   oproepen naar bibliotheek I / O-functies.

In scenario 1 wijzigt een van de voorgestelde wijzigingen de volgorde van schrijfbewerkingen in vluchtige gegevens.

In scenario 2 wijzigt geen van beide door u voorgestelde wijzigingen de reeks. Dus ze zijn toegestaan ​​volgens de "as-if" -regel (1.9 / 1):

... conformerende implementaties zijn   vereist om (alleen) de. te emuleren   waarneembaar gedrag van het abstract   machine ...

Om te vertellen dat dit is gebeurd, moet u de machinecode bekijken, een foutopsporingsprogramma gebruiken of ongedefinieerd of niet-gespecificeerd gedrag uitlokken waarvan u het resultaat weet over uw implementatie. Een implementatie kan bijvoorbeeld garanties bieden over de weergave dat gelijktijdig uitgevoerde threads van hetzelfde geheugen hebben, maar dat valt buiten de scope van de C ++ -standaard. Dus hoewel de standaard een bepaalde codetransformatie mogelijk zou maken, zou een bepaalde implementatie het kunnen uitsluiten, op grond van het feit dat het niet weet of uw code in een multi-threaded programma zal worden uitgevoerd.

Als u waarneembaar gedrag zou gebruiken om te testen of het opnieuw ordenen is gebeurd of niet (bijvoorbeeld het afdrukken van de waarden van variabelen in de bovenstaande code), dan zou het natuurlijk niet door de standaard worden toegestaan.


11
2018-03-29 00:51



Voor scenario 1 zou de compiler geen van de door u genoemde nabestellingen moeten uitvoeren. Voor scenario 2 hangt het antwoord mogelijk af van:

  • en of het b en c variabelen zijn zichtbaar buiten de huidige functie (hetzij door niet lokaal te zijn of hun adres te hebben doorgegeven)
  • met wie je praat (blijkbaar is er onenigheid over hoe string volatile is in C / C ++)
  • uw compiler-implementatie

Dus (mijn eerste antwoord verzachtend), zou ik zeggen dat als je in scenario 2 afhankelijk bent van bepaald gedrag, je het zou moeten behandelen als niet-draagbare code waarvan het gedrag op een bepaald platform zou zijn bepaald door wat dan ook de documentatie van de implementatie kan erop wijzen (en als de documenten er niets over zeggen, dan heeft u pech met een gegarandeerd gedrag.

van C99 5.1.2.3/2 "Uitvoering van het programma":

Toegang tot een vluchtig object, het aanpassen van een object, het wijzigen van een bestand of het aanroepen van een functie die een van die bewerkingen uitvoert, zijn allemaal neveneffecten, dit zijn wijzigingen in de status van de uitvoeringsomgeving. Evaluatie van een expressie kan bijwerkingen veroorzaken. Op bepaalde gespecificeerde punten in de uitvoeringssequentie, sequentie-punten genoemd, zijn alle bijwerkingen van eerdere evaluaties voltooid en zullen er geen bijwerkingen van opeenvolgende evaluaties hebben plaatsgevonden.

...

(lid 5) De minste vereisten voor een conforme implementatie zijn:

  • Op volgpunten zijn vluchtige objecten stabiel in de zin dat eerdere toegangen voltooid zijn en dat daaropvolgende toegangen nog niet hebben plaatsgevonden.

Hier is een beetje van wat Herb Sutter te zeggen heeft over het vereiste gedrag van volatile toegangen in C / C ++ (van "volatile vs. volatile" http://www.ddj.com/hpc-high-performance-computing/212701484):

hoe zit het in de buurt van gewoon lezen en schrijven - kunnen die nog steeds worden nabesteld rond niet-optimale lees- en schrijfbewerkingen? Tegenwoordig is er geen praktisch draagbaar antwoord, omdat de C / C ++-compilerimplementaties erg verschillen en waarschijnlijk niet snel zullen convergeren. Bijvoorbeeld, een interpretatie van de C ++ standaard houdt in dat gewone reads vrij in beide richtingen kunnen bewegen over een C / C ++ vluchtig lezen of schrijven, maar dat een gewone write helemaal niet kan bewegen over een C / C ++ volatile read of write - die zou C / C ++ vluchtig maken, beide minder beperkend en meer restrictief, respectievelijk, dan een geordend atoom. Sommige compilerververanciers ondersteunen die interpretatie; anderen optimaliseren helemaal niet over vluchtige lees- of schrijfbewerkingen; en weer anderen hebben hun eigen voorkeurssemantiek.

En voor wat het waard is, documenteert Microsoft het volgende voor de C / C ++ volatile sleutelwoord (als Microsoft-sepcific):

  • Een schrijven naar een vluchtig object (vluchtig schrijven) heeft Release-semantiek; een verwijzing naar een globaal of statisch object dat optreedt voordat een schrijfactie naar een vluchtig object in de instructiereeks plaatsvindt vóór die vluchtige schrijfbewerking in het gecompileerde binaire bestand.

  • Een read van een vluchtig object (volatile read) heeft Acantire semantics; een verwijzing naar een globaal of statisch object dat optreedt nadat een vluchtig geheugen in de instructiereeks is gelezen nadat dat vluchtige in het gecompileerde binaire bestand is gelezen.

Hierdoor kunnen vluchtige objecten worden gebruikt voor geheugensloten en releases in multithreaded applicaties.


4
2018-03-29 00:44



Vluchtig is geen geheugenomheining. Toewijzingen naar B en C in fragment # 2 kunnen worden geëlimineerd of worden uitgevoerd wanneer. Waarom zou je willen dat de verklaringen in # 2 het gedrag van # 1 veroorzaken?


2
2018-03-29 00:45



Sommige compilers beschouwen toegang tot volatiel gekwalificeerde objecten als een geheugenomheining. Anderen doen niet. Sommige programma's zijn geschreven om dat te vereisen volatile werkt als een hek. Anderen zijn dat niet.

Code die is geschreven om omheiningen te vereisen die worden uitgevoerd op platforms die deze bieden, kan beter worden uitgevoerd dan code die is geschreven om geen omheiningen te vereisen, die op platforms worden uitgevoerd die deze niet leveren, maar code waarvoor omheiningen vereist zijn, zal niet werken als ze niet worden aangeboden . Code die geen omheiningen vereist, loopt vaak langzamer op platforms die deze bieden dan code waarvoor de omheiningen vereist zijn, en implementaties die omheiningen bieden, voeren die code langzamer uit dan die welke dat niet doen.

Een goede benadering kan zijn om een ​​macro te definiëren semi_volatile als uitdijend naar niets op systemen waar volatile impliceert een geheugenomheining of naar volatileop systemen waar dit niet het geval is. Als variabelen die moeten worden besteld met betrekking tot andere volatile variabelen maar niet aan elkaar kwalificeren als semi-volatileen die macro is correct gedefinieerd, betrouwbare werking zal worden bereikt op systemen met of zonder geheugenomheiningen, en de meest efficiënte werking die kan worden bereikt op systemen met omheiningen zal worden bereikt. Als een compiler daadwerkelijk een kwalificatie implementeert die werkt zoals vereist, semivolatile, het kan worden gedefinieerd als een macro die die kwalificatie gebruikt en nog betere code behaalt.

IMHO, dat is een gebied dat de standaard echt zou moeten aanpakken, omdat de betrokken concepten op veel platforms van toepassing zijn, en elk platform waar hekken niet zinvol zijn, kan ze gewoon negeren.


0
2017-07-08 00:22