Semaphore Example






3.28/5 (11 votes)
A Semaphore example.
Introduction
This is sample program to explain how semaphores work. I have taken the production and consumption logic to explain the working of semaphores. As you know, semaphores are used for resource counting. Here, always the number of produced units is 10 greater than the consumption, i.e., a buffer of 10 is always maintained. The buffer can't go beyond 10. Similarly the consumption can't exceed the production.
Background
A user who starts to work on thread synchronization can take this as a starting point to go. I have taken a simple program.
Using the code
This application has a dialog. And there are two threads which individually run to the production/consumption. These threads can be controlled by two events to start/stop. When the production is started, the thread runs and it checks that the buffer has reached the size of 10. If not, the thread continues to do production, otherwise it stops...
Similarly when the consumption is started, it starts to consume from the buffer. As the consumption is being done continuously, both production and consumption run simultaneously. When the consumption stops, the buffer will reach a size of 10 [on waiting on the semaphore] and the production is stopped automatically.
When the production is stopped, the consumption thread can take a maximum of 10 from the buffer and after that the consumption is stopped as the buffer is zeroed [on waiting on the semaphore]. As some of you mentioned, I missed the explanation on the semaphore [that's is the objective of the article!!!!].
As I said, we have production and consumption threads. There are two semaphore objects which control the resource counts. One is to account the production units m_hProduction
and the other is meant for the consumption m_hCustomer
.
The production thread is created with an initial count of 0 and a max count of 10. As it is created with an initial count of 0
,
this is in a non-signaled state.
The consumption semaphore object is created with an initial count of 10 and a max count 10. So this is signaled.
Now let me talk about how the threads use this object....
As we know, the customer semaphore is initially in the signaled state. So the production thread successfully passes the first check. Now when the start button of the production thread is pressed, the production event becomes signaled and the thread does the production. After doing the production, the current count of the production semaphore is increased by 1 and the thread again waits for the customer semaphore. If it is signaled then the loop continues, otherwise it waits till the customer semaphore is signaled. Each time as the thread waiting on the semaphore is being scheduled [because the semaphore is in signaled state], the current resource count of the customer is decreased by one. Here the current count of the customer semaphore is decreased by one. So the loop can iterate 10 times, and after that the current count of the customer semaphore goes to 0, and the production thread goes into a wait state.... Now the current count of production is raised to 10.
Now say, the start button of the consumption thread is started. So the consumption event is signaled. Now the consumption thread waiting on the production semaphore is scheduled as it is in the signaled state. After doing the consumption, it increases the consumption semaphore by 1 and it waits on the production semaphore. If the consumption thread is scheduled over waiting for the production semaphore, the current count of the production semaphore is decreased by 1.
I'll explain two cases here:
- The production thread is started and it runs till
cur.count
of the production semaphore is 10. Now press the stop button to make the production event to non signaled. Now the production thread is waiting. Now start the consumption thread. Here the production semaphore'scur.count
is 10 and this thread can iterate 10 times [to consume 10 units] and now the production semaphore'scur.count
becomes 0 and the consumption thread is stopped. So now both the threads get stopped. - Both the threads are running parallel. The production semaphore is signaled by the production thread, so the consumption thread waiting on the production semaphore is scheduled. As the consumption thread is scheduled, it signals the consumption semaphore, so the production thread waiting on this object is scheduled. So both threads run simultaneously. Production and consumption happen in parallel.
unsigned WINAPI Production(PVOID dlgPtr )
{
CSemaphore_ExDlg* pDlg = (CSemaphore_ExDlg*)(dlgPtr);
//Do the production if there is any customer request. Otherwise wait for the
//customer's request
DWORD res = WaitForSingleObject( m_hCustomer,INFINITE );
//if the object is signaled, do the production
int i = 0, j = 0;
static int Ctr = 0;
while ( res == WAIT_OBJECT_0 )
{
//Check for the production event signal
WaitForSingleObject( hEventProd, INFINITE );
containerArray[j++] = i++;
Ctr++;
g_Var++;
CString str;
str.Format("%d", g_Var );
pDlg->m_statNew.SetWindowText( str );
//Set the value in the progress bar
(pDlg->m_ctrlProd).SetValue( Ctr );
if( j >= MAX_ELEMENTS )
j = j % MAX_ELEMENTS;
//Production is done. So signal the customer
LONG pOldVal;
ReleaseSemaphore( m_hProduction,1,&pOldVal );
//Do the production continuously
res = WaitForSingleObject( m_hCustomer,INFINITE );
Sleep( 50 );
}
return 0;
}
unsigned WINAPI Consumption(PVOID dlgPtr )
{
CSemaphore_ExDlg* pDlg = (CSemaphore_ExDlg*)(dlgPtr);
//Consume the product if already some produced goods are available
DWORD res = WaitForSingleObject( m_hProduction,INFINITE );
//if the object is signaled, do the production
int i = 0, j = 0;
static int Ctr = 0;
while ( res == WAIT_OBJECT_0 )
{
//Check for the consumer event object
WaitForSingleObject( hEventCons, INFINITE );
containerArray[j++] = -1;
Ctr++;
(pDlg->m_ctrlCons).SetValue(Ctr );
if( j >= MAX_ELEMENTS )
j = j % MAX_ELEMENTS;
//Consumption is done. So signal the empty object
ReleaseSemaphore( m_hCustomer,1,0 );
//Do the consumption continuously
res = WaitForSingleObject( m_hProduction,INFINITE );
Sleep( 50 );
}
return 0;
}
I find this code explains more clearly about how semaphores work.
History
This is the second version. As the first version was missing the explanation, I have added it. Please let me if you need more.....