2016-08-29 2 views
4

Im folgenden C99-Beispiel wird das Flag buffer_full garantiert gesetzt (auch wenn -O2-Optimierungen aktiviert sind), nachdem der Puffer gelesen oder geschrieben wurde? Oder brauche ich eine Speicherbarriere, um die richtige Reihenfolge zu gewährleisten?Benötige ich eine Speicherbarriere?

Ich erwarte, dass dies auf einem System ausgeführt wird, bei dem ausgerichtete 32-Bit-Lese- und Schreibvorgänge atomar sind.

Angenommen, nur eine Instanz jedes Threads wird ausgeführt und keine anderen Threads greifen auf buffer oder buffer_full zu.

char buffer[100]; 
int buffer_full; 

// write interesting data to the buffer. does not read. 
void fill_buffer(char* buffer, size_t buffsz); 
// read the interesting data in the buffer. does not write. 
void use_buffer(const char* buffer, size_t buffsz); 

void writer_thread() 
{ 
    if (!buffer_full) { 
     fill_buffer(buffer, sizeof(buffer)); 
     // is a memory barrier needed here? 
     buffer_full = 1; 
    } 
} 

void reader_thread() 
{ 
    if (buffer_full) { 
     use_buffer(buffer, sizeof(buffer)); 
     // is a memory barrier needed here? 
     buffer_full = 0; 
    } 
} 
+0

Ihre Frage ist ein bisschen schwer zu verstehen, aber ich nehme an, Sie meinen, * ist der Zugriff auf 'buffer_full' atomare *? Im Prinzip ist es so. –

+0

Ich denke, ist auch plattformabhängig. Wenn "int" nativ ist, ist es atomar, und soweit die Variable eine nicht ausgerichtete Adresse hat. – LPs

+0

Sortieren von. Ich möchte sicherstellen, dass ein leerer Puffer nie gelesen wird und niemals ein voller Puffer geschrieben wird. Ich bin hauptsächlich besorgt über die Bestellung. Wird die Einstellung buffer_full jemals neu geordnet, bevor sie entweder vom Compiler oder von der Hardware im Code angezeigt wird? – PaulH

Antwort

3

interpretiere ich Sie fragen, ob ein Compiler die Zuordnungen buffer_full mit den Anrufen zu fill_buffer() und read_buffer() neu anordnen können. Eine solche Optimierung (und jegliche Optimierung) ist nur erlaubt, wenn sie das extern beobachtbare Verhalten des Programms nicht verändert.

In diesem Fall, weil buffer_full externe Verknüpfung hat, ist es unwahrscheinlich, dass der Compiler zuversichtlich sein kann, ob die Optimierung zulässig ist. Dies kann möglicherweise der Fall sein, wenn die Definitionen der Funktionen fill_buffer() und use_buffer() und jeder von ihnen selbst aufgerufenen Funktion usw. lauten. sind in der gleichen Übersetzungseinheit mit den writer_thread() und reader_thread() Funktionen, aber das hängt etwas von ihren Implementierungen ab. Wenn ein kompilierender Compiler nicht sicher ist, dass die Optimierung zulässig ist, darf er sie nicht ausführen.

Sofern Ihre Namensgebung impliziert, dass die beiden Funktionen in verschiedenen Threads ausgeführt werden, jedoch dann ohne Synchronisierungsaktionen wie eine Speicherbarriere, können Sie nicht über die relative Ordnung sicher sein, in dem ein Thread wahrnehmen Modifikationen geteilt , nicht _Atomic, nicht volatile Daten, die von einem anderen Thread ausgeführt werden.

Wenn außerdem ein Thread eine nicht atomare Variable schreibt und ein anderer Thread auf dieselbe Variable zugreift (lesen oder schreiben), dann gibt es ein Datenrennen, es sei denn, eine Synchronisationsaktion oder eine atomare Operation zwischen den beiden interagiert in jeder möglichen Summe Reihenfolge der Operationen. volatile Variablen helfen hier nicht wirklich (siehe Why is volatile not considered useful in multithreaded C or C++ programming?). Wenn Sie jedoch buffer_full atomar machen oder wenn Sie Ihre Funktionen mit atomaren Lese- und Schreiboperationen implementieren, dann dient dies dazu, Datenrennen zu vermeiden, die nicht nur diese Variable, sondern auch buffer (für Ihre derzeitige Codestruktur) beinhalten.

+0

Danke! Würde es einen Unterschied machen, ob der Puffer oder die Flagge atomar wären? – PaulH

+0

edit: realisierte ich sagte "atomare" wenn ich im letzten Kommentar "flüchtig" sagen wollte. – PaulH

+0

Ich habe der Frage hinzugefügt, dass dies die einzigen 2 Threads sind, die auf 'buffer' und' buffer_full' zugreifen. Ist der Mutex immer noch erforderlich? Wenn ja, kannst du mir helfen zu verstehen warum? – PaulH

Verwandte Themen