Что такое семафоры в программировании и зачем они нужны?
Семафор — инструмент для управления синхронизацией. Это целочисленная переменная, которую одновременно используют сразу несколько процессов. Основная цель использования семафора — это синхронизация процессов и управление доступом к общему ресурсу в многопроцессорной среде.
У семафоров них есть две основные операции:
- Операция ожидания уменьшает значение аргумента S, если оно положительное. Если значение S отрицательно или равно нулю, операция не выполняется:
wait(S)
{
while (S<=0);
S--;
}
- Операция подачи сигнала увеличивает значение своего аргумента S:
signal(S)
{
S++;
}
Есть два типа семафоров:
- Универсальный или считающий семафор — это семафор с целочисленными значениями и неограниченной областью значений. Эти семафоры используются для координации доступа к ресурсам, где счетчик семафоров — это количество доступных ресурсов. Если ресурсы добавляются, счетчик семафоров автоматически увеличивается, а если ресурсы удаляются, счетчик уменьшается. Считающий семафор используется для работы с несколькими процессами и решения проблем синхронизации.
- Двоичный семафор — имеет значение, ограниченное 0 и 1. Операция ожидания работает только тогда, когда семафор равен 1, а операция сигнала завершается успешно, когда семафор равен 0. Если вам знаком механизм работы мьютексов, то может показаться, что нет разницы, что использовать — двоичный семафор или мьютекс.
Но на самом деле семафор — это сигнальный механизм, а мьютекс — это механизм блокировки.
Работа семафоров на примерах из жизни
Ситуация первая: есть два банкомата, и только два человека одновременно могут снять деньги. Когда человек заходит в банк, он получает разрешение, если имеются свободные ресурсы (банкоматы), и проверяет, какой из банкоматов свободен для использования. Как только он получает доступ к банкомату, то блокирует его, вводит PIN-код и снимает деньги. Только после этого освобождается семафор.
Ситуация вторая: у входа в ресторан стоят 20 человек. В этом случае количество семафоров совпадает с количеством ресурсов (свободных столиков), равным 10. Чтобы клиент мог войти в ресторан, он должен получить разрешение. После этого посетитель выбирает один из доступных столов. Как только его заказ будет выполнен, он освобождает ресурс, делая его доступным для других клиентов в очереди. В этом случае семафор гарантирует, что одновременно только 10 клиентов могут войти в ресторан и сделать заказ.
В обоих случаях семафор проверяет наличие доступных ресурсов и блокирует возможность их использовать, если лимит ресурсов исчерпан. Когда количество ресурсов становится больше нуля, цикл повторяется и семафор выдает разрешение на их использование.
Пример кода с использованием семафоров
Давайте посмотрим, как семафоры работают в коде C++:
#include<iostream>
#include<mutex>
using namespace std;
struct semaphore
{
int mutex;
int rcount;
int rwait;
bool wrt;
};
void addR(struct semaphore *s)
{
if(s->mutex == 0 && s->rcount == 0)
{
cout<<"\nSorry, File open in Write mode.\nNew Reader added to queue.\n";
s->rwait++;
}
else
{
cout<<"\nReader Process added.\n";
s->rcount++;
s->mutex--;
}
return ;
}
void addW(struct semaphore *s)
{
if(s->mutex==1)
{
s->mutex--;
s->wrt=1;
cout<<"\nWriter Process added.\n";
}
else if(s->wrt)
cout<<"\nSorry, Writer already operational.\n";
else
cout<<"\nSorry, File open in Read mode.\n";
return ;
}
void remR(struct semaphore *s)
{
if(s->rcount == 0) cout<<"\nNo readers to remove.\n";
else
{
cout<<"\nReader Removed.\n";
s->rcount--;
s->mutex++;
}
return ;
}
void remW(struct semaphore *s)
{
if(s->wrt==0) cout<<"\nNo Writer to Remove\n";
else
{
cout<<"\nWriter Removed\n";
s->mutex++;
s->wrt=0;
if(s->rwait!=0)
{
s->mutex-=s->rwait;
s->rcount=s->rwait;
s->rwait=0;
cout<<"waiting Readers Added:"<<s->rcount<<endl;
}
}
}
int main()
{
struct semaphore S1={1,0,0};
while(1)
{
cout<<"Options :-\n1.Add Reader.\n2.Add Writer.\n3.Remove Reader.\n4.Remove Writer.\n5.Exit.\n\n\tChoice : ";
int ch;
cin>>ch;
switch(ch)
{
case 1: addR(&S1); break;
case 2: addW(&S1); break;
case 3: remR(&S1); break;
case 4: remW(&S1); break;
case 5: cout<<"\n\tGoodBye!";break;
default: cout<<"\nInvalid Entry!";
}
}
return 0;
}
В результате получим:
Options :-
1.Add Reader.
2.Add Writer.
3.Remove Reader.
4.Remove Writer.
5.Exit.
Choice : 1
Reader Process added.
Options :-
1.Add Reader.
2.Add Writer.
3.Remove Reader.
4.Remove Writer.
5.Exit.
Choice : 1
Reader Process added.
Options :-
1.Add Reader.
2.Add Writer.
3.Remove Reader.
4.Remove Writer.
5.Exit.
Choice : 1
Reader Process added.
Options :-
1.Add Reader.
2.Add Writer.
3.Remove Reader.
4.Remove Writer.
5.Exit.
Choice : 3
Reader Removed.
Options :-
1.Add Reader.
2.Add Writer.
3.Remove Reader.
4.Remove Writer.
5.Exit.
Choice : 2
Sorry, File open in Read mode.
Options :-
1.Add Reader.
2.Add Writer.
3.Remove Reader.
4.Remove Writer.
5.Exit.
Choice : 3
Reader Removed.
Options :-
1.Add Reader.
2.Add Writer.
3.Remove Reader.
4.Remove Writer.
5.Exit.




Сообщить об опечатке
Текст, который будет отправлен нашим редакторам: