Я изучаю многопоточность и пытаюсь понять концепцию семафоров и взаимных исключений. Большинство примеров, которые я нашел в Интернете, используют какую-то библиотеку (например, pthread
) для реализации семафора или мьютекса, но меня больше интересует реализация простого семафора, который устанавливает критическую секцию — не более одного потока, обращающегося к определенный участок памяти.
Я считаю, что для этой задачи мне понадобится мьютекс (также известный как двоичный семафор, если я правильно понимаю терминологию). Я вижу, как семафор может предотвратить состояние гонки, «заблокировав» часть кода для одного потока, но что предотвращает возникновение состояния гонки на самом семафоре?
Я предполагаю, что двоичный семафор содержит значение int для отслеживания блокировки:
Semaphore
---------
int lock = 1;
unsigned P(void){
if(lock > 0){
lock--;
return 0; /* success */
}
return 1; /* fail */
}
void V(void){
lock++;
}
Предположим, что два потока вызывают функцию P
одновременно, они оба достигают проверки if(lock > 0)
одновременно и оценивают условие как true — это создает состояние гонки, при котором обоим потокам предоставляется доступ к той же области памяти в то же время.
Так что же предотвращает возникновение этого состояния гонки в реальных реализациях семафоров?