Semaphores in C++
In this tutorial, we will learn about semaphore in C++. We will also see a sample code to understand it better.
What is a semaphore?
A semaphore is a non-negative variable which can be used to access a common resource of the operating system.
Semaphores are used to overcome the critical section problem. The critical section is an area in a program that is used to access common resources. But, two programs cannot enter the critical section simultaneously Semaphores come in handy in such situations.
Types of semaphores in C++:
There are two types of semaphores:
- Binary semaphores: As the name suggests, a binary semaphore can take only two values, 0 and 1. The default value of a binary semaphore is 1. It is also known as a mutex lock.
- Counting semaphores: These have values which may range from 0 to any number ‘n’. They have an unrestricted domain.
Operations on semaphores in C++
Semaphores solve the critical section problem by using two atomic operations, wait() and signal().
wait operation: if the value of the semaphore s is negative or zero, no operation is performed. If the value of s is positive, it is decremented. The pseudocode for wait operation is as follows:
wait(s)
{
while(s<=0);
s--;
}
signal operation: This operation is used to increase the value of the semaphore s. The pseudocode for signal operation is as follows:
signal(s)
{
s++
}Sample code for implementing semaphore in C++:
The following code can be used to effectively implement and understand semaphores in 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;
}
The above-given code implements the reader-writer problem using semaphores. The output of the code will look something like this:
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.With this, we come to the end of this tutorial.
Also read:
void remR(struct semaphore *s){
if(s->rcount == 0) cout<<"\nNo readers to remove.\n";
else{
cout<rcount–;
if (rcount==0) s->mutex++; //think thats missing
// s->mutex++;
}
return ;
}