Windows NT Systems Programming: Spring 2000

[ Home | Syllabus | Course Notes | Assignments | Search]


Synchronization


Critical Sections

VARIABLE:

FUNCTIONS:


Critical Section Example (listing 6.4)

#include <windows.h>
//. . .
volatile INT count;
CRITICAL_SECTION critSec;

void CountThread(INT iterations)
{
//. . .
  for (i=0; i<iterations; i++)
  {
    EnterCriticalSection(&critSec);
    x=count;
    x++;
    count=x;
    LeaveCriticalSection(&critSec);
  }
}


void main(void)
{
 
// . . .
  InitializeCriticalSection(&critSec);

  for (i=0; i<numThreads; i++)
  {
    // create a thread and pass it the pointer 
    // to its "params" struct
    handles[i]=CreateThread(0, 0,
      (LPTHREAD_START_ROUTINE) CountThread, 
      (VOID *) 25000, 0, &threadID);
  }

  WaitForMultipleObjects(numThreads, handles, 
    TRUE, INFINITE);  

  DeleteCriticalSection(&critSec);
}

MUTEX (BINARY SEMAPHORE)

Can be used across processes by naming it.

VARIABLE:

FUNCTIONS:


MUTEX example

void CountThread(INT iterations)
{
  INT i;
  INT x;
  HANDLE mutex;

  mutex = CreateMutex(0, FALSE, "counterMutex");  // only first thread actually creates it

  for (i=0; i<iterations; i++)
  {
    WaitForSingleObject(mutex, INFINITE); 
    x=count;
    x++;
    count=x;
    ReleaseMutex(mutex); 
  }

  CloseHandle(mutex); 
}


Events

In automatic mode, like a MUTEX, in manual can be used to release a number of waiting processes/threads.

 


WaitFor...

Used to wait for many things (p. 257)

Also allows a time out value.

Multiple Objects can be waited for


Solution to Bounded Buffer Problem

Bounded buffer is a classic problem in operating system synchronization. A producer and consumer exchange information using a fixed number of buffers. They can run at different rates and should never get into an inconsistent state

There are two solutions available

  1. Using separate processes for the consumer and producer
  2. Using separate threads for the producer and consumer

We will examine the later here. Points to be demonstrated:


#include <windows.h>
#include <iostream.h>
#include <stdlib.h>
const int NBUFFERS = 3;	// allow 3 buffers for bounded buffer
typedef struct{
	int bufID;
	int bufValue;
} Buffer;

Buffer commonBuffers[NBUFFERS];

void producer(DWORD myId); // producer thread function
void consumer(DWORD myId); // consumer thread function

void main(void)
{
	HANDLE empty, full; // "pointer" to the semaphores
	HANDLE testHandles[2]; // "pointers" to the threads
	DWORD threadId; // receives threadID assigned (not used mostly)
	int id = 1; // one parameter to thread is an integer ID
	
	// Create the semaphores
	empty = CreateSemaphore(0,NBUFFERS,NBUFFERS, "NTcourse.semaphore.empty");
// Create a counting semaphore with initial value NBUFFERS and max value NBUFFERS
// This semaphore controls the empty buffer (initially all buffers are empty) 
	full = CreateSemaphore(0,0,NBUFFERS, "NTcourse.semaphore.full");
// Create a counting semaphore with initial value NBUFFERS and max value NBUFFERS
// This semaphore controls the full buffers (initially no full buffers)
	
	// Start producer (with argument, id = 1)
	testHandles[0] = CreateThread(0,0,
		(LPTHREAD_START_ROUTINE) producer,
		(void*)id, 0, &threadId);
	id++;
	// Start consumer (with argument ,id = 2)
	testHandles[1] = CreateThread(0,0,
		(LPTHREAD_START_ROUTINE) consumer,
		(void*)id, 0, &threadId);

	WaitForMultipleObjects(2, testHandles, TRUE, INFINITE);
	// wait until both threads are done 
	CloseHandle(empty);
	CloseHandle(full);
	
}

//***************************************************************
// illustrates two processes cooperating in a producer/consumer relationship
// The producer/consumer relationship is managed by two semaphores
// EMPTY and FULL, When EMPTY the producer can produce into empty buffer,
// when FULL the consumer can consume buffer.
// the buffer is passed through shared memory using the file mapping mechanism
// This code demonstrates the consumer side
// AUTHOR: Chris Wild
// DATE: September 10, 1997
//***************************************************************

void producer(DWORD myId)
{
	HANDLE empty, full;
	
	empty = OpenSemaphore(SEMAPHORE_ALL_ACCESS,FALSE, "NTcourse.semaphore.empty");
// opens semaphore created in the main thread
	if(empty == NULL) {
		cout << "Error opening empty: " 
			<< GetLastError() << endl;
		ExitProcess(1);
	}
	
	full = OpenSemaphore(SEMAPHORE_ALL_ACCESS, FALSE, "NTcourse.semaphore.full");
	if(full == NULL) {
		cout << "Error opening full: " 
			<< GetLastError() << endl;
		ExitProcess(1);
	}
	
	// enter a loops producing some things
	int bufN = 0;
	for(int i = 0; i < 10; i++) {
		// First wait for previous resource to be empty (consumed)
		cout << "PRODUCER: waiting for empty buffer\n";
		WaitForSingleObject(empty, INFINITE);
	// Have empty resource - use it to produce		
	// put code here to produce something	
		commonBuffers[bufN].bufID = bufN; // buffer number
		commonBuffers[bufN].bufValue = 1000*i; // buffer value
		bufN = (bufN+1) % NBUFFERS;
		
		ReleaseSemaphore(full,1,0);	// signals production
	}
	CloseHandle(empty);	
	CloseHandle(full);
}


void consumer(DWORD myId)
{
	HANDLE empty, full;	// control bounded buffer access
	
	
	empty = OpenSemaphore(SEMAPHORE_ALL_ACCESS,FALSE, "NTcourse.semaphore.empty");
	if(empty == NULL) {
		cout << "Error opening empty: " 
			<< GetLastError() << endl;
		ExitProcess(1);
	}
	
	full = OpenSemaphore(SEMAPHORE_ALL_ACCESS, FALSE, "NTcourse.semaphore.full");
	if(full == NULL) {
		cout << "Error opening full: " 
			<< GetLastError() << endl;
		ExitProcess(1);
	}
	
	// enter a loops consuming some things
	int bufN = 0;
	DWORD returnValue;
	while(true) {
		// First wait for buffer to be produced
		returnValue = WaitForSingleObject(full, 10000); // wait 10 seconds
		if( returnValue == WAIT_TIMEOUT) {
			cout << "Waited too long for producer - assumed died\n";
			break;
		}
		// Have full buffer - consume it
		bufN = (bufN+1) % NBUFFERS;
		ReleaseSemaphore(empty,1,0);	// signals empty
	}
	CloseHandle(empty);
	CloseHandle(full);
	
}


Copyright chris wild 1999/2000.
For problems or questions regarding this web contact [Dr. Wild].
Last updated: February 24, 2000.