Funktioniert mutex_unlock als Speicherzaun?

Die Situation, die ich beschreiben werde, tritt auf einem iPad 4 (ARMv7s) auf, bei dem Posix-Libs zum Sperren / Entsperren von Mutex-Elementen verwendet werden. Ich habe ähnliche Dinge auf anderen ARMv7-Geräten gesehen (siehe unten). Ich nehme an, dass für jede Lösung ein allgemeinerer Blick auf das Verhalten von Mutexen und Speicherzäunen für ARMv7 erforderlich ist.

Pseudocode für das Szenario:

Thread 1 - Daten erzeugen:

void ProduceFunction() {
  MutexLock();
  int TempProducerIndex = mSharedProducerIndex; // Take a copy of the int member variable for Producers Index
  mSharedArray[TempProducerIndex++] = NewData; // Copy new Data into array at Temp Index 
  mSharedProducerIndex = TempProducerIndex; // Signal consumer data is ready by assigning new Producer Index to shared variable
  MutexUnlock();
}

Thread 2 - Daten verbrauchen:

void ConsumingFunction () {
  while (mConsumerIndex != mSharedProducerIndex) {
    doWorkOnData (mSharedArray[mConsumerIndex++]);
  }
}

Früher (als das Problem auf dem iPad 2 auftrat) habe ich das geglaubtmSharedProducerIndex = TempProducerIndex wurde nicht atomar ausgeführt und daher geändert, um ein zu verwendenAtomicCompareAndSwap zuweisenmSharedProducerIndex. Das hat bis jetzt geklappt, aber es stellte sich heraus, dass ich mich geirrt hatte und der Fehler zurückgekommen ist. Ich denke, das 'Update' hat gerade das Timing geändert.

Ich bin nun zu dem Schluss gekommen, dass das eigentliche Problem eine nicht ordnungsgemäße Ausführung der Schreibvorgänge innerhalb der Mutex-Sperre ist, d. H. Wenn entweder der Compiler oder die Hardware beschlossen haben, die Reihenfolge zu ändern:

mSharedArray[TempProducerIndex++] = NewData; // Copy new Data into array at Temp Index 
mSharedProducerIndex = TempProducerIndex;  // Signal consumer data is ready by assigning new Producer Index to shared variable

... zu:

mSharedProducerIndex = TempProducerIndex; // Signal consumer data is ready by assigning new Producer Index to shared variable
mSharedArray[TempProducerIndex++] = NewData; // Copy new Data into array at Temp Index 

... und dann hat der Verbraucher den Hersteller verschachtelt, die Daten wären noch nicht geschrieben worden, als der Verbraucher versucht hat, sie zu lesen.

Nach einigem Lesen der Speicherbarrieren dachte ich daher, ich würde versuchen, das Signal an den Verbraucher außerhalb dermutex_unlock, in der Annahme, dass das Entsperren eine Speicherbarriere / einen Speicherzaun erzeugen würde, die / der sicherstellen würdemSharedArray wurde geschrieben an:

mSharedArray[TempProducerIndex++] = NewData;  // Copy new Data into array at Temp Index 
MutexUnlock();
mSharedProducerIndex = TempProducerIndex; // Signal consumer data is ready by assigning new Producer Index to shared variable

Dies scheitert jedoch immer noch und führt mich zu der Frage, ob amutex_unlock wird auf jeden Fall als Schreibzaun fungieren oder nicht?

Ich habe auch gelesenein Artikel von HP was darauf hindeutet, dass Compiler Code in (aber nicht aus) verschieben könntencrit_secs. Also auch nach der obigen Änderung das Schreiben vonmSharedProducerIndex könnte vor der Barriere sein. Gibt es Meilen für diese Theorie?

Durch Hinzufügen eines expliziten Zauns wird das Problem behoben:

mSharedArray[TempProducerIndex++] = NewData; // Copy new Data into array at Temp Index 
OSMemoryBarrier();
mSharedProducerIndex = TempProducerIndex; // Signal consumer data is ready by assigning new Producer Index to shared variable

Ich denke daher, dass ich das Problem verstehe und dass ein Zaun erforderlich ist, aber jeder Einblick in das Verhalten des Entsperrens und warum es keine Barriere zu sein scheint, wäre wirklich nützlich.

BEARBEITEN:

Zum Fehlen eines Mutex im Consumer Thread: Ich verlasse mich auf das Schreiben desint mSharedProducerIndex eine einzige Anweisung zu sein und daher zu hoffen, dass der Verbraucher entweder den neuen oder den alten Wert liest. Beides sind gültige Zustände, und das vorausgesetztmSharedArray wird der Reihe nach geschrieben (d. h. vor dem SchreibenmSharedProducerIndex) wäre in Ordnung, aber nach dem, was bisher gesagt wurde, kann ich darauf keine Antwort geben.

Aus der gleichen Logik geht hervor, dass die aktuelle Barrierenlösung ebenso fehlerhaft ist wie diemSharedProducerIndex write könnte innerhalb der Barriere verschoben und daher möglicherweise falsch angeordnet werden.

Ist es empfehlenswert, dem Verbraucher einen Mutex hinzuzufügen, nur um als Lesebarriere zu fungieren, oder gibt es einenpragma oder eine Anweisung zum Deaktivieren der Ausführung außerhalb der Reihenfolge auf dem Produzenten, wie zEIEIO auf PPC?

Antworten auf die Frage(2)

Ihre Antwort auf die Frage