Jest sobie lista wskaźnikowa, kolejka LIFO elementów przekazywanych z wątków pobocznych do wątku głównego:
Element * volatile lista;
Wątki producentów wrzucają na listę elementy zatrzaskując muteks:
muteks->Zatrzasnij();
element->nastepny = lista;
lista = element;
muteks->Zwolnij();
Konsumentem jest wątek główny, który co każdą główną pętlę programu pobiera wszystkie dostępne elementy:
void Konsumuj()
{
Element *elementy;
muteks->Zatrzasnij();
elementy = lista;
lista = NULL;
muteks->Zwolnij();
while (elementy != NULL) {
/* ... */
}
}
int main()
{
for (;;) {
/* ... */
Konsumuj();
/* ... */
}
}
Zastanawiam się, czy poprawnym i dobrym rozwiązaniem będzie sprawdzenie, czy lista jest pusta zanim zatrzaśniemy muteks w celu zwiększenia wydajności (lista jest zazwyczaj pusta):
void Konsumuj()
{
if (lista == NULL) return; // sprawdzamy, czy lista jest pusta bez zatrzaskiwania muteksa
Element *elementy;
muteks->Zatrzasnij();
elementy = lista;
lista = NULL;
muteks->Zwolnij();
while (elementy != NULL) {
/* ... */
}
}
Nawet jeśli czasem lista == NULL
zwróci wartość inną od prawidłowej to nic się nie powinno stać. Pytanie, czy to przekłamanie może występować notorycznie? Czy volatile
rozwiewa wszelkie wątpliwości? Czy może jest to złe rozwiązanie z jakichś innych względów i olać tą krztynę wydajności?
Pytanie zadaję w kontekście wieloplatformowym.