Czy mutex_unlock działa jako ogrodzenie pamięci?
Sytuacja, którą opiszę, ma miejsce na iPadzie 4 (ARMv7s), używając libów posix do blokowania / odblokowywania muteksu. Widziałem podobne rzeczy na innych urządzeniach ARMv7 (patrz poniżej), więc przypuszczam, że każde rozwiązanie będzie wymagało bardziej ogólnego spojrzenia na zachowanie muteksów i ogrodzeń pamięci dla ARMv7.
Pseudo kod scenariusza:
Wątek 1 - tworzenie danych:
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();
}
Wątek 2 - pobieranie danych:
void ConsumingFunction () {
while (mConsumerIndex != mSharedProducerIndex) {
doWorkOnData (mSharedArray[mConsumerIndex++]);
}
}
Wcześniej (gdy problem pojawił się na iPadzie 2), wierzyłem w tomSharedProducerIndex = TempProducerIndex
nie był wykonywany atomowo, a zatem zmieniono go na użycieAtomicCompareAndSwap
przypisaćmSharedProducerIndex
. To działało do tego momentu, ale okazało się, że się myliłem i błąd wrócił. Myślę, że „poprawka” zmieniła tylko trochę czasu.
Doszedłem do wniosku, że faktycznym problemem jest nieuporządkowane wykonywanie zapisów w blokadzie mutexów, tj. Jeśli kompilator lub sprzęt postanowili zmienić kolejność:
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
... do:
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
... a następnie konsument przeplatał producenta, dane nie byłyby jeszcze zapisane, gdy konsument próbował je odczytać.
Po przeczytaniu barier pamięci pomyślałem więc, że spróbuję przenieść sygnał do konsumenta pozamutex_unlock
, wierząc, że odblokowanie wytworzy barierę pamięci / ogrodzenie, które zapewnimSharedArray
napisano do:
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
To jednak nadal się nie udaje i prowadzi mnie do pytania, czymutex_unlock
na pewno będzie działać jako ogrodzenie do pisania, czy nie?
Czytałem teżartykuł od HP który sugerował, że kompilatory mogą przenosić kod do (ale nie z)crit_sec
s. Więc nawet po powyższej zmianie, piszęmSharedProducerIndex
może być przed barierą. Czy jest jakiś przebieg tej teorii?
Dodając wyraźne ogrodzenie, problem zniknie:
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
Dlatego myślę, że rozumiem ten problem i że wymagane jest ogrodzenie, ale każdy wgląd w zachowanie odblokowania i dlaczego nie wydaje się, aby wykonywał barierę, byłby naprawdę użyteczny.
EDYTOWAĆ:
Jeśli chodzi o brak muteksu w wątku konsumenckim: polegam na zapisieint mSharedProducerIndex
będąc pojedynczą instrukcją, a zatem mając nadzieję, że konsument przeczyta nową lub starą wartość. Albo są ważnymi stanami i zapewniają tomSharedArray
jest napisany w kolejności (tj. przed napisaniemmSharedProducerIndex
) byłoby OK, ale z tego, co do tej pory powiedziano, nie mogę na to odpowiedzieć.
Zgodnie z tą samą logiką wydaje się, że obecne rozwiązanie barierowe jest również wadliwe, podobnie jakmSharedProducerIndex
zapis może zostać przeniesiony do wnętrza bariery i dlatego może zostać nieprawidłowo uporządkowany.
Czy zaleca się dodanie muteksu do konsumenta, aby działać jako bariera odczytu, czy też istniejepragma
lub instrukcja wyłączenia wykonania poza zamówieniem u producenta, jakEIEIO
na PPC?