Windows NT Systems
Programming
[ Home
| Syllabus |Course Notes]
Process Communications
Memory-Mapped Files/Shared Memory
Shared memory allows fast
communications between two processes on same machine
- File Mapping allows file to be
mapped into memory
- Programs manipulate the in
memory buffer using normal programming constructs
- Buffer is saved under explicit
program control
- Different parts of the file
can be viewed at the same time or different times
- These in-memory file buffers
can be shared among processes
CreateFileMapping (p. 79)
- HANDLE of open file (or
0xFFFFFFFF for paging file)
- security
- DWORD protect // access mode
READ/WRITE
- DWORD sizeHigh // max size
high order 32 bits
- DWORD sizeLow // max size low
order 32 bits
- mapName // for other processes
to access
This returns a HANDLE to the mapped
file
MapViewOfFile
- HANDLE returned by
CreateFileMapping above
- DWORD access // READ/WRITE
- DWORD offsetHigh // offset in
file where to start mapping (high order 32 bits)
- DWORD offsetLow // low order
32 bits
- DWORD number // number of
bytes to include in view
This returns a pointer to the view
of the mapped file.
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 (p. 196)
- Window control stuff
- HANDLES to standard I/O
- command line arguments
- inherit HANDLES to other
objects
- environment variables
- other stuff
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);
//. . .
Copyright chris wild 1997.
For problems or questions regarding this web contact [Dr. Wild].
Last updated: September 10, 1997.