[header.htm]

Process Communications

 


Process Synchronization Comparison

sync.jpg (70000 bytes)


Memory-Mapped Files/Shared Memory

Shared memory allows fast communications between two processes on same machine


CreateFileMapping (p. 106)

This returns a HANDLE to the mapped file


MapViewOfFile (p.107)

This returns a pointer to the view of the mapped file.

 


OpenFileMapping (p. 107)

used for two processes to share memory

This returns a HANDLE to the mapped file


CASE STUDY:
Producer/Consumer Bounded Buffer Problem

(source code here for producer)

 

//***************************************************************
// illustrates two processes cooperating in a producer/consumer relationship
// This code demonstrates the parent side of handle inheritance.
// 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.
// Buffers are passed through shared memory implemented as a memory mapped file
// AUTHOR: Chris Wild
// DATE: September 10, 1997
//***************************************************************

#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; 

void main(void)
{
	HANDLE empty, full; 
	HANDLE mapFileHandle; 
	Buffer* commonBuffers; 
	
	
	// Create the semaphores
	empty = CreateSemaphore(0,NBUFFERS,NBUFFERS, "NTcourse.semaphore.empty"); 
	full = CreateSemaphore(0,0,NBUFFERS, "NTcourse.semaphore.full");
	cout << "created semaphores\n";
	
	// create in-memory file for Interprocess Communications
	mapFileHandle = CreateFileMapping( 
		(HANDLE) 0xFFFFFFFF, // unnamed file maps to virtual memory
		0,	// security
		PAGE_READWRITE,	// access to file
		0,	// high word of file size
		NBUFFERS*sizeof(Buffer), // size of memory mapped area
		"commonBuffer");	// name it to share with other processes
	commonBuffers = (Buffer*) MapViewOfFile(mapFileHandle, 
		FILE_MAP_WRITE,
		0,	// High offset
		0,	// Low offest
		0);	// 0 for mapping entire file

    // 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); 
		commonBuffers[bufN].bufID = bufN; 
		commonBuffers[bufN].bufValue = 1000*i;
		bufN = (bufN+1) % NBUFFERS; 
		// Have empty resource - use it to produce		
		// put code here to produce something	
		cout << "PRODUCER: producing a new buffer\n";
		ReleaseSemaphore(full,1,0);	// signals production 
	}
	
	CloseHandle(empty);
	CloseHandle(full);
	CloseHandle(mapFileHandle);
}

Consumer

(source code here for consumer)

//...
	HANDLE empty, full;	// control bounded buffer access
	HANDLE mapFileHandle;	// used to access the shared 
	Buffer* commonBuffers; // pointer into memory mapped file to array of buffer structures
	
	
	cout << "Entered consumer: v2\n";
    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);
	}
	
	mapFileHandle = OpenFileMapping(PAGE_READWRITE, 
		FALSE,	// child cannot inherit
		"commonBuffer");
	if(mapFileHandle == NULL) {
		cout << "Error opening commonBuffer: " 
			<< GetLastError() << endl;
		ExitProcess(1);
	}
	commonBuffers = (Buffer*) MapViewOfFile(mapFileHandle,
		FILE_MAP_READ, 
		0,	// High offset
		0,	// Low offest
		0);	// 0 for mapping entire file
	if(commonBuffers == NULL) {
		cout << "Error mapping file: " 
			<< GetLastError() << endl;
		ExitProcess(1);
	}
	
	
	
	// enter a loops consuming some things
	int bufN = 0;
	DWORD returnValue;
	while(true) {
		// First wait for buffer to be produced
		cout << "CONSUMER: waiting for full buffer\n";
		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
		cout << "CONSUMER: emptied buffer: " << 
			commonBuffers[bufN].bufID << 
			" with value: " << commonBuffers[bufN].bufValue << endl;
		bufN = (bufN+1) % NBUFFERS;
		ReleaseSemaphore(empty,1,0); 	// signals empty
	}
	CloseHandle(empty);
	CloseHandle(full);
	CloseHandle(mapFileHandle);
	
}

CreateProcess


CreateProcess Example

(source code here for create process producer)

 

//...
  STARTUPINFO startUpInfo; 
  PROCESS_INFORMATION procInfo; 
  BOOL success;
  char s[100]; // command line arguments (unused in this example) 
  // . . .
 GetStartupInfo(&startUpInfo);  // short cut to fill most of the windowing parameters for child environment
  // Create the child process
  success=CreateProcess("consumer.exe", s, 0, 0, FALSE,  
    CREATE_NEW_CONSOLE, 
    0, 0, &startUpInfo, &procInfo);
  if (!success)
    cout << "Error creating process v2: " 
      << GetLastError() << endl;
// . . .

  WaitForSingleObject(procInfo.hProcess, INFINITE); 
//. . .

[footer.htm]