Unit OS3: Concurrency Unit OS3: Concurrency
3.4. Windows APIs for Synchronization and 3.4. Windows APIs for Synchronization and
Inter-Process Communication
Inter-Process Communication
Copyright Notice Copyright Notice
© 2000-2005 David A. Solomon and Mark Russinovich
© 2000-2005 David A. Solomon and Mark Russinovich
These materials are part of the
These materials are part of the Windows Operating Windows Operating System Internals Curriculum Development Kit,
System Internals Curriculum Development Kit, developed by David A. Solomon and Mark E.
developed by David A. Solomon and Mark E.
Russinovich with Andreas Polze Russinovich with Andreas Polze
Microsoft has licensed these materials from David Microsoft has licensed these materials from David Solomon Expert Seminars, Inc. for distribution to Solomon Expert Seminars, Inc. for distribution to academic organizations solely for use in academic academic organizations solely for use in academic environments (and not for commercial use)
environments (and not for commercial use)
Roadmap for Section 3.4.
Roadmap for Section 3.4.
Windows API constructs for synchronization and Windows API constructs for synchronization and interprocess communication
interprocess communication Synchronization
Synchronization
Critical sections Critical sections
Mutexes Mutexes
Semaphores Semaphores Event objects Event objects
Synchronization through interprocess communication Synchronization through interprocess communication
Anonymous pipes Anonymous pipes
Named pipes Named pipes
Mailslots Mailslots
Critical Sections Critical Sections
Only usable from within the same process Only usable from within the same process
Critical sections are initialized and deleted but do not have handles Critical sections are initialized and deleted but do not have handles Only one thread at a time can be in a critical section
Only one thread at a time can be in a critical section
A thread can enter a critical section multiple times - however, the A thread can enter a critical section multiple times - however, the number of Enter- and Leave-operations must match
number of Enter- and Leave-operations must match
Leaving a critical section before entering it may cause deadlocks Leaving a critical section before entering it may cause deadlocks No way to test whether another thread is in a critical section
No way to test whether another thread is in a critical section
VOID InitializeCriticalSection( LPCRITICAL_SECTION sec );
VOID DeleteCriticalSection( LPCRITICAL_SECTION sec );
VOID EnterCriticalSection( LPCRITICAL_SECTION sec );
VOID LeaveCriticalSection( LPCRITICAL_SECTION sec );
BOOL TryEnterCriticalSection ( LPCRITICAL_SECTION sec );
Critical Section Example Critical Section Example
/* counter is global, shared by all threads */
/* counter is global, shared by all threads */
volatile int counter = 0;
volatile int counter = 0;
CRITICAL_SECTION crit;
CRITICAL_SECTION crit;
InitializeCriticalSection ( &crit );
InitializeCriticalSection ( &crit );
/* … main loop in any of the threads */
/* … main loop in any of the threads */
while (!done) { while (!done) {
_try { _try {
EnterCriticalSection ( &crit );
EnterCriticalSection ( &crit );
counter += local_value;
counter += local_value;
LeaveCriticalSection ( &crit );
LeaveCriticalSection ( &crit );
} }
_finally { LeaveCriticalSection ( &crit ); } _finally { LeaveCriticalSection ( &crit ); } }}
DeleteCriticalSection( &crit );
DeleteCriticalSection( &crit );
Synchronizing Threads with Synchronizing Threads with
Kernel Objects Kernel Objects
The following kernel objects can be used The following kernel objects can be used to synchronize threads:
to synchronize threads:
Processes Processes
Threads Threads
Files Files
Console input Console input
File change notifications File change notifications Mutexes
Mutexes
Events (auto-reset + manual-reset) Events (auto-reset + manual-reset) Waitable timers
Waitable timers
DWORD WaitForSingleObject( HANDLE hObject, DWORD dwTimeout );
DWORD WaitForMultipleObjects( DWORD cObjects,
LPHANDLE lpHandles, BOOL bWaitAll, DWORD dwTimeout );
Wait Functions - Details Wait Functions - Details
WaitForSingleObject():
WaitForSingleObject():
hObject specifies kernel object hObject specifies kernel object
dwTimeout specifies wait time in msec dwTimeout specifies wait time in msec
dwTimeout == 0 - no wait, check whether object is signaled dwTimeout == 0 - no wait, check whether object is signaled
dwTimeout == INFINITE - wait forever dwTimeout == INFINITE - wait forever
WaitForMultipleObjects():
WaitForMultipleObjects():
cObjects <= MAXIMUM_WAIT_OBJECTS (64) cObjects <= MAXIMUM_WAIT_OBJECTS (64)
lpHandles - pointer to array identifying these objects lpHandles - pointer to array identifying these objects
bWaitAll - whether to wait for first signaled object or all objects bWaitAll - whether to wait for first signaled object or all objects
Function returns index of first signaled object Function returns index of first signaled object
Side effects:
Side effects:
Mutexes, auto-reset events and waitable timers will be reset to Mutexes, auto-reset events and waitable timers will be reset to non-signaled state after completing wait functions
non-signaled state after completing wait functions
Mutexes Mutexes
Mutexes work across processes Mutexes work across processes
First thread has to call CreateMutex() First thread has to call CreateMutex()
When sharing a mutex, second thread (process) calls CreateMutex() When sharing a mutex, second thread (process) calls CreateMutex() or OpenMutex()
or OpenMutex()
fInitialOwner == TRUE gives creator immediate ownership fInitialOwner == TRUE gives creator immediate ownership
Threads acquire mutex ownership using WaitForSingleObject() or Threads acquire mutex ownership using WaitForSingleObject() or WaitForMultipleObjects()
WaitForMultipleObjects()
ReleaseMutex() gives up ownership ReleaseMutex() gives up ownership CloseHandle() will free mutex object CloseHandle() will free mutex object
HANDLE CreateMutex( LPSECURITY_ATTRIBUTE lpsa, BOOL fInitialOwner, LPTSTR lpszMutexName );
HANDLE OpenMutex( LPSECURITY_ATTRIBUTE lpsa, BOOL fInitialOwner, LPTSTR lpszMutexName );
BOOL ReleaseMutex( HANDLE hMutex );
Mutex Example Mutex Example
/* counter is global, shared by all threads */
/* counter is global, shared by all threads */
volatile int done, counter = 0;
volatile int done, counter = 0;
HANDLE mutex = CreateMutex( NULL, FALSE, NULL );
HANDLE mutex = CreateMutex( NULL, FALSE, NULL );
/* main loop in any of the threads, ret is local */
/* main loop in any of the threads, ret is local */
DWORD ret;
DWORD ret;
while (!done) { while (!done) {
ret = WaitForSingleObject( mutex, INFINITE );
ret = WaitForSingleObject( mutex, INFINITE );
if (ret == WAIT_OBJECT_0) if (ret == WAIT_OBJECT_0) counter += local_value;
counter += local_value;
else
else /* mutex was abandoned *//* mutex was abandoned */
break;
break; /* exit the loop *//* exit the loop */
ReleaseMutex( mutex );
ReleaseMutex( mutex );
}}
CloseHandle( mutex );
CloseHandle( mutex );
Comparison - POSIX mutexes Comparison - POSIX mutexes
POSIX pthreads specification supports mutexes POSIX pthreads specification supports mutexes
Synchronization among threads in same process Synchronization among threads in same process
Five basic functions:
Five basic functions:
pthread_mutex_init() pthread_mutex_init()
pthread_mutex_destroy() pthread_mutex_destroy() pthread_mutex_lock() pthread_mutex_lock() pthread_mutex_unlock() pthread_mutex_unlock() pthread_mutex_trylock() pthread_mutex_trylock()
Comparison:
Comparison:
pthread_mutex_lock() will block - equivalent to pthread_mutex_lock() will block - equivalent to WaitForSingleObject( hMutex );
WaitForSingleObject( hMutex );
pthread_mutex_trylock() is nonblocking (polling) - equivalent to pthread_mutex_trylock() is nonblocking (polling) - equivalent to WaitForSingleObject() with timeout == 0
WaitForSingleObject() with timeout == 0
Semaphores Semaphores
Semaphore objects are used for resource counting Semaphore objects are used for resource counting
A semaphore is signaled when count > 0 A semaphore is signaled when count > 0
Threads/processes use wait functions Threads/processes use wait functions
Each wait function decreases semaphore count by 1 Each wait function decreases semaphore count by 1 ReleaseSemaphore() may increment count by any value ReleaseSemaphore() may increment count by any value ReleaseSemaphore() returns old semaphore count
ReleaseSemaphore() returns old semaphore count
HANDLE CreateSemaphore( LPSECURITY_ATTRIBUTE lpsa, LONG cSemInit, LONG cSemMax,
LPTSTR lpszSemName );
HANDLE OpenSemaphore( LPSECURITY_ATTRIBUTE lpsa, LONG cSemInit, LONG cSemMax,
LPTSTR lpszSemName );
HANDLE ReleaseSemaphore( HANDLE hSemaphore,
LONG cReleaseCount, LPLONG lpPreviousCount );
Events Events
Multiple threads can be released when a single event is signaled (barrier Multiple threads can be released when a single event is signaled (barrier
synchronization) synchronization)
Manual-reset event can signal several thread simultaneously; must be reset Manual-reset event can signal several thread simultaneously; must be reset manually
manually
PulseEvent() will release all threads waiting on a manual-reset event and PulseEvent() will release all threads waiting on a manual-reset event and automatically reset the event
automatically reset the event
Auto-reset event signals a single thread; event is reset automatically Auto-reset event signals a single thread; event is reset automatically fInitialState == TRUE - create event in signaled state
fInitialState == TRUE - create event in signaled state
HANDLE CreateEvent( LPSECURITY_ATTRIBUTE lpsa, BOOL fManualReset, BOOL fInititalState
LPTSTR lpszEventName );
BOOL SetEvent( HANDLE hEvent );
BOOL ResetEvent( HANDLE hEvent );
BOOL PulseEvent( HANDLE hEvent );
Comparison - Comparison -
POSIX condition variables POSIX condition variables
pthread’s condition variables are comparable to events pthread’s condition variables are comparable to events
pthread_cond_init() pthread_cond_init()
pthread_cond_destroy() pthread_cond_destroy()
Wait functions:
Wait functions:
pthread_cond_wait() pthread_cond_wait()
pthread_cond_timedwait() pthread_cond_timedwait()
Signaling:
Signaling:
pthread_cond_signal() - one thread pthread_cond_signal() - one thread
pthread_cond_broadcast() - all waiting threads pthread_cond_broadcast() - all waiting threads
No exact equivalent to manual-reset events
No exact equivalent to manual-reset events
Anonymous pipes Anonymous pipes
Half-duplex character-based IPC Half-duplex character-based IPC
cbPipe: pipe byte size; zero == default cbPipe: pipe byte size; zero == default
Read on pipe handle will block if pipe is empty Read on pipe handle will block if pipe is empty Write operation to a full pipe will block
Write operation to a full pipe will block Anonymous pipes are oneway
Anonymous pipes are oneway
BOOL CreatePipe( PHANDLE phRead, PHANDLE phWrite,
LPSECURITY_ATTRIBUTES lpsa, DWORD cbPipe )
main
prog1 prog2
pipe
I/O Redirection using I/O Redirection using
an Anonymous Pipe an Anonymous Pipe
/* Create default size anonymous pipe, handles are inheritable. */
/* Create default size anonymous pipe, handles are inheritable. */
if (!CreatePipe (&hReadPipe, &hWritePipe, &PipeSA, 0)) { if (!CreatePipe (&hReadPipe, &hWritePipe, &PipeSA, 0)) {
fprintf(stderr, “Anon pipe create failed\n”); exit(1);
fprintf(stderr, “Anon pipe create failed\n”); exit(1);
}}
/* Set output handle to pipe handle, create first processes. */
/* Set output handle to pipe handle, create first processes. */
StartInfoCh1.hStdInput = GetStdHandle (STD_INPUT_HANDLE);
StartInfoCh1.hStdInput = GetStdHandle (STD_INPUT_HANDLE);
StartInfoCh1.hStdError = GetStdHandle (STD_ERROR_HANDLE);
StartInfoCh1.hStdError = GetStdHandle (STD_ERROR_HANDLE);
StartInfoCh1.hStdOutput = hWritePipe;
StartInfoCh1.hStdOutput = hWritePipe;
StartInfoCh1.dwFlags = STARTF_USESTDHANDLES;
StartInfoCh1.dwFlags = STARTF_USESTDHANDLES;
if (!CreateProcess (NULL, (LPTSTR)Command1, NULL, NULL, TRUE, if (!CreateProcess (NULL, (LPTSTR)Command1, NULL, NULL, TRUE,
0, NULL, NULL, &StartInfoCh1, &ProcInfo1)) { 0, NULL, NULL, &StartInfoCh1, &ProcInfo1)) { fprintf(stderr, “CreateProc1 failed\n”); exit(2);
fprintf(stderr, “CreateProc1 failed\n”); exit(2);
}}
CloseHandle (hWritePipe);
CloseHandle (hWritePipe);
Pipe example (contd.) Pipe example (contd.)
/* Repeat (symmetrically) for the second process. */
/* Repeat (symmetrically) for the second process. */
StartInfoCh2.hStdInput = hReadPipe;
StartInfoCh2.hStdInput = hReadPipe;
StartInfoCh2.hStdError = GetStdHandle (STD_ERROR_HANDLE);
StartInfoCh2.hStdError = GetStdHandle (STD_ERROR_HANDLE);
StartInfoCh2.hStdOutput = GetStdHandle (STD_OUTPUT_HANDLE);
StartInfoCh2.hStdOutput = GetStdHandle (STD_OUTPUT_HANDLE);
StartInfoCh2.dwFlags = STARTF_USESTDHANDLES;
StartInfoCh2.dwFlags = STARTF_USESTDHANDLES;
if (!CreateProcess (NULL, (LPTSTR)targv, NULL, NULL,TRUE,/* Inherit if (!CreateProcess (NULL, (LPTSTR)targv, NULL, NULL,TRUE,/* Inherit handles. */
handles. */
0, NULL, NULL, &StartInfoCh2, &ProcInfo2)) { 0, NULL, NULL, &StartInfoCh2, &ProcInfo2)) {
fprintf(stderr, “CreateProc2 failed\n”); exit(3);
fprintf(stderr, “CreateProc2 failed\n”); exit(3);
}}
CloseHandle (hReadPipe);
CloseHandle (hReadPipe);
/* Wait for both processes to complete. */
/* Wait for both processes to complete. */
WaitForSingleObject (ProcInfo1.hProcess, INFINITE);
WaitForSingleObject (ProcInfo1.hProcess, INFINITE);
WaitForSingleObject (ProcInfo2.hProcess, INFINITE);
WaitForSingleObject (ProcInfo2.hProcess, INFINITE);
CloseHandle (ProcInfo1.hThread); CloseHandle (ProcInfo1.hProcess);
CloseHandle (ProcInfo1.hThread); CloseHandle (ProcInfo1.hProcess);
CloseHandle (ProcInfo2.hThread); CloseHandle (ProcInfo2.hProcess);
CloseHandle (ProcInfo2.hThread); CloseHandle (ProcInfo2.hProcess);
return 0;
return 0;
Named Pipes Named Pipes
Message oriented:
Message oriented:
Reading process can read varying-length messages precisely as Reading process can read varying-length messages precisely as sent by the writing process
sent by the writing process
Bi-directional Bi-directional
Two processes can exchange messages over the same pipe Two processes can exchange messages over the same pipe
Multiple, independent instances of a named pipe:
Multiple, independent instances of a named pipe:
Several clients can communicate with a single server Several clients can communicate with a single server using the same instance
using the same instance
Server can respond to client using the same instance Server can respond to client using the same instance
Pipe can be accessed over the network Pipe can be accessed over the network
location transparency location transparency
Convenience and connection functions Convenience and connection functions
Using Named Pipes Using Named Pipes
lpszPipeName:
lpszPipeName: \\.\pipe\[\\.\pipe\[path]pipenamepath]pipename
Not possible to create a pipe on remote machine (. – local machine) Not possible to create a pipe on remote machine (. – local machine) fdwOpenMode:
fdwOpenMode:
PIPE_ACCESS_DUPLEX, PIPE_ACCESS_INBOUND, PIPE_ACCESS_DUPLEX, PIPE_ACCESS_INBOUND, PIPE_ACCESS_OUTBOUND
PIPE_ACCESS_OUTBOUND fdwPipeMode:
fdwPipeMode:
PIPE_TYPE_BYTE or PIPE_TYPE_MESSAGE PIPE_TYPE_BYTE or PIPE_TYPE_MESSAGE
PIPE_READMODE_BYTE or PIPE_READMODE_MESSAGE PIPE_READMODE_BYTE or PIPE_READMODE_MESSAGE PIPE_WAIT or PIPE_NOWAIT (will ReadFile block?)
PIPE_WAIT or PIPE_NOWAIT (will ReadFile block?)
HANDLE CreateNamedPipe (LPCTSTR lpszPipeName, DWORD fdwOpenMode, DWORD fdwPipMode DWORD nMaxInstances, DWORD cbOutBuf, DWORD cbInBuf, DWORD dwTimeOut,
LPSECURITY_ATTRIBUTES lpsa );
Use same flag settings for all instances of a named pipe
Named Pipes (contd.) Named Pipes (contd.)
nMaxInstances:
nMaxInstances:
Number of instances, Number of instances,
PIPE_UNLIMITED_INSTANCES: OS choice based on resources PIPE_UNLIMITED_INSTANCES: OS choice based on resources dwTimeOut
dwTimeOut
Default time-out period (in msec) for WaitNamedPipe() Default time-out period (in msec) for WaitNamedPipe() First CreateNamedPipe creates named pipe
First CreateNamedPipe creates named pipe
Closing handle to last instance deletes named pipe Closing handle to last instance deletes named pipe Polling a pipe:
Polling a pipe:
Nondestructive – is there a message waiting for ReadFile Nondestructive – is there a message waiting for ReadFile
BOOL PeekNamedPipe (HANDLE hPipe,
LPVOID lpvBuffer, DWORD cbBuffer,
LPDWORD lpcbRead, LPDWORD lpcbAvail, LPDWORD lpcbMessage);
Named Pipe Client Connections Named Pipe Client Connections
CreateFile with named pipe name:
CreateFile with named pipe name:
\\.\pipe\[
\\.\pipe\[path]pipenamepath]pipename
\\servername\pipe\[path]pipename\\servername\pipe\[path]pipename
First method gives better performance (local server) First method gives better performance (local server)
Status Functions:
Status Functions:
GetNamedPipeHandleState GetNamedPipeHandleState SetNamedPipeHandleState SetNamedPipeHandleState
GetNamedPipeInfo GetNamedPipeInfo
Convenience Functions Convenience Functions
WriteFile / ReadFile sequence:
WriteFile / ReadFile sequence:
BOOL TransactNamedPipe( HANDLE hNamedPipe, LPVOID lpvWriteBuf, DWORD cbWriteBuf, LPVOID lpvReadBuf, DWORD cbReadBuf, LPDOWRD lpcbRead, LPOVERLAPPED lpa);
• CreateFile / WriteFile / ReadFile / CloseHandle:
- dwTimeOut: NMPWAIT_NOWAIT, NMPWAIT_WIAT_FOREVER, NMPWAIT_USE_DEFAULT_WAIT
BOOL CallNamedPipe( LPCTSTR lpszPipeName, LPVOID lpvWriteBuf, DWORD cbWriteBuf, LPVOID lpvReadBuf, DWORD cbReadBuf, LPDWORD lpcbRead, DWORD dwTimeOut);
Server: eliminate the polling loop Server: eliminate the polling loop
lpo == NULL:
lpo == NULL:
Call will return as soon as there is a client connection Call will return as soon as there is a client connection
Returns false if client connected between CreateNamed Pipe call Returns false if client connected between CreateNamed Pipe call and ConnectNamedPipe()
and ConnectNamedPipe()
Use DisconnectNamedPipe to free the handle for connection from Use DisconnectNamedPipe to free the handle for connection from another client
another client
WaitNamedPipe():
WaitNamedPipe():
Client may wait for server‘s ConnectNamedPipe() Client may wait for server‘s ConnectNamedPipe()
Security rights for named pipes:
Security rights for named pipes:
GENERIC_READ, GENERIC_WRITE, SYNCHRONIZE GENERIC_READ, GENERIC_WRITE, SYNCHRONIZE
BOOL ConnectNamedPipe (HANDLE hNamedPipe, LPOVERLAPPED lpo );
Comparison with UNIX Comparison with UNIX
UNIX FIFOs are similar to a named pipe UNIX FIFOs are similar to a named pipe
FIFOs are half-duplex FIFOs are half-duplex
FIFOs are limited to a single machine FIFOs are limited to a single machine
FIFOs are still byte-oriented, so its easiest to use fixed-size records FIFOs are still byte-oriented, so its easiest to use fixed-size records in client/server applications
in client/server applications
Individual read/writes are atomic Individual read/writes are atomic
A server using FIFOs must use a separate FIFO for each client‘s A server using FIFOs must use a separate FIFO for each client‘s response, although all clients can send requests via a single, well response, although all clients can send requests via a single, well known FIFO
known FIFO
Mkfifo() is the UNIX counterpart to CreateNamedPipe() Mkfifo() is the UNIX counterpart to CreateNamedPipe() Use sockets for networked client/server scenarios
Use sockets for networked client/server scenarios
Client Example using Named Pipe Client Example using Named Pipe
WaitNamedPipe (ServerPipeName, NMPWAIT_WAIT_FOREVER);
WaitNamedPipe (ServerPipeName, NMPWAIT_WAIT_FOREVER);
hNamedPipe = CreateFile (ServerPipeName, GENERIC_READ | GENERIC_WRITE, hNamedPipe = CreateFile (ServerPipeName, GENERIC_READ | GENERIC_WRITE,
0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hNamedPipe == INVALID_HANDLE_VALUE) { if (hNamedPipe == INVALID_HANDLE_VALUE) {
fptinf(stderr, Failure to locate server.\n"); exit(3);
fptinf(stderr, Failure to locate server.\n"); exit(3);
}}
/* Write the request. */
/* Write the request. */
WriteFile (hNamedPipe, &Request, MAX_RQRS_LEN, &nWrite, NULL);
WriteFile (hNamedPipe, &Request, MAX_RQRS_LEN, &nWrite, NULL);
/* Read each response and send it to std out. */
/* Read each response and send it to std out. */
while (ReadFile (hNamedPipe, Response.Record, MAX_RQRS_LEN, &nRead, NULL)) while (ReadFile (hNamedPipe, Response.Record, MAX_RQRS_LEN, &nRead, NULL))
printf ("%s", Response.Record);
printf ("%s", Response.Record);
CloseHandle (hNamedPipe);
CloseHandle (hNamedPipe);
return 0;
return 0;
Server Example Using a Named Server Example Using a Named Pipe Pipe
hNamedPipe = CreateNamedPipe (SERVER_PIPE, PIPE_ACCESS_DUPLEX, hNamedPipe = CreateNamedPipe (SERVER_PIPE, PIPE_ACCESS_DUPLEX,
PIPE_READMODE_MESSAGE | PIPE_TYPE_MESSAGE | PIPE_WAIT, PIPE_READMODE_MESSAGE | PIPE_TYPE_MESSAGE | PIPE_WAIT, 1, 0, 0, CS_TIMEOUT, pNPSA);
1, 0, 0, CS_TIMEOUT, pNPSA);
while (!Done) { while (!Done) {
printf ("Server is awaiting next request.\n");
printf ("Server is awaiting next request.\n");
if (!ConnectNamedPipe (hNamedPipe, NULL) if (!ConnectNamedPipe (hNamedPipe, NULL)
|| !ReadFile (hNamedPipe, &Request, RQ_SIZE, &nXfer, NULL)) {
|| !ReadFile (hNamedPipe, &Request, RQ_SIZE, &nXfer, NULL)) { fprintf(stderr, “Connect or Read Named Pipe error\n”); exit(4);
fprintf(stderr, “Connect or Read Named Pipe error\n”); exit(4);
}}
printf( “Request is: %s\n", Request.Record);
printf( “Request is: %s\n", Request.Record);
/* Send the file, one line at a time, to the client. */
/* Send the file, one line at a time, to the client. */
fp = fopen (File, "r");
fp = fopen (File, "r");
while ((fgets (Response.Record, MAX_RQRS_LEN, fp) != NULL)) while ((fgets (Response.Record, MAX_RQRS_LEN, fp) != NULL))
WriteFile (hNamedPipe, &Response.Record, WriteFile (hNamedPipe, &Response.Record,
(strlen(Response.Record) + 1) * TSIZE, &nXfer, NULL);
(strlen(Response.Record) + 1) * TSIZE, &nXfer, NULL);
fclose (fp);
fclose (fp);
DisconnectNamedPipe (hNamedPipe);
DisconnectNamedPipe (hNamedPipe);
}} /* End of server operation. *//* End of server operation. */
Windows IPC - Mailslots Windows IPC - Mailslots
Broadcast mechanism:
Broadcast mechanism:
One-directional One-directional
Mutliple writers/multiple readers (frequently: one-to-many comm.) Mutliple writers/multiple readers (frequently: one-to-many comm.) Message delivery is unreliable
Message delivery is unreliable
Can be located over a network domain Can be located over a network domain
Message lengths are limited (w2k: < 426 byte) Message lengths are limited (w2k: < 426 byte) Operations on the mailslot:
Operations on the mailslot:
Each reader (server) creates mailslot with CreateMailslot() Each reader (server) creates mailslot with CreateMailslot() Write-only client opens mailslot with CreateFile() and
Write-only client opens mailslot with CreateFile() and
uses WriteFile() – open will fail if there are no waiting readers uses WriteFile() – open will fail if there are no waiting readers Client‘s message can be read by all servers (readers)
Client‘s message can be read by all servers (readers) Client lookup:
Client lookup: \\*\mailslot\mailslotname\\*\mailslot\mailslotname
Client will connect to every server in network domain Client will connect to every server in network domain
Mailslots bear some nasty implementation details;
they are almost never used
Locate a server via mailslot Locate a server via mailslot
hMS = CreateMailslot(
“\\.\mailslot\status“);
ReadFile(hMS, &ServStat);
/* connect to server */
hMS = CreateMailslot(
“\\.\mailslot\status“);
ReadFile(hMS, &ServStat);
/* connect to server */
App client 0
App client n
Mailslot Servers
While (...) { Sleep(...);
hMS = CreateFile(
“\\.\mailslot\status“);
...
WriteFile(hMS, &StatInfo }
App Server
Mailslot Client
Message is sent periodically
Creating a mailslot Creating a mailslot
lpszName points to a name of the form lpszName points to a name of the form
\\.\mailslot\[path]name
\\.\mailslot\[path]name
Name must be unique; mailslot is created locally Name must be unique; mailslot is created locally
cbMaxMsg is msg size in byte cbMaxMsg is msg size in byte dwReadTimeout
dwReadTimeout
Read operation will wait for so many msec Read operation will wait for so many msec
0 – immediate return 0 – immediate return
MAILSLOT_WAIT_FOREVER – infinite wait MAILSLOT_WAIT_FOREVER – infinite wait
HANDLE CreateMailslot(LPCTSTR lpszName, DWORD cbMaxMsg,
DWORD dwReadTimeout,
LPSECURITY_ATTRIBUTES lpsa);
Opening a mailslot Opening a mailslot
CreateFile with the following names:
CreateFile with the following names:
\\.\mailslot\[path]name
\\.\mailslot\[path]name - retrieve handle for local mailslot - retrieve handle for local mailslot
\\host\mailslot\[path]name
\\host\mailslot\[path]name - retrieve handle - retrieve handle for mailslot on specified host
for mailslot on specified host
\\domain\mailslot\[path]name
\\domain\mailslot\[path]name - returns handle representing all - returns handle representing all mailslots on machines in the domain
mailslots on machines in the domain
\\*\mailslot\[path]name
\\*\mailslot\[path]name - returns handle representing mailslots - returns handle representing mailslots on machines in the system‘s primary domain: max mesg. len:
on machines in the system‘s primary domain: max mesg. len:
400 bytes 400 bytes
Client must specifiy FILE_SHARE_READ flag Client must specifiy FILE_SHARE_READ flag
GetMailslotInfo() and SetMailslotInfo() are similar to their GetMailslotInfo() and SetMailslotInfo() are similar to their named pipe counterparts
named pipe counterparts
Further Reading Further Reading
Mark E. Russinovich and David A. Solomon, Microsoft Windows Mark E. Russinovich and David A. Solomon, Microsoft Windows Internals, 4th Edition, Microsoft Press, 2004.
Internals, 4th Edition, Microsoft Press, 2004.
Chapter 3 - System Mechanisms Chapter 3 - System Mechanisms Synchronization (from pp.149) Synchronization (from pp.149)
Named Pipes and Mailslots (from pp. 804) Named Pipes and Mailslots (from pp. 804)
Jeffrey Richter, Programming Applications for Microsoft Windows, Jeffrey Richter, Programming Applications for Microsoft Windows, 4th Edition, Microsoft Press, September 1999.
4th Edition, Microsoft Press, September 1999.
Chapter 10 - Thread Synchronization Chapter 10 - Thread Synchronization
Critical Sections, Mutexes, Semaphores, Events (from pp. 315) Critical Sections, Mutexes, Semaphores, Events (from pp. 315)
Johnson M. Hart, Win32 System Programming: A Windows® 2000 Johnson M. Hart, Win32 System Programming: A Windows® 2000 Application Developer's Guide, 2nd Edition, Addison-Wesley, 2000.
Application Developer's Guide, 2nd Edition, Addison-Wesley, 2000.
Source Code References Source Code References
Windows Research Kernel sources Windows Research Kernel sources
\base\ntos\ke – primitive kernel support
\base\ntos\ke – primitive kernel support
eventobj.c - Event object eventobj.c - Event object mutntobj.c – Mutex object mutntobj.c – Mutex object
semphobj.c – Semaphore object semphobj.c – Semaphore object timerobj.c, timersup.c – Timers timerobj.c, timersup.c – Timers wait.c, waitsup.c – Wait support wait.c, waitsup.c – Wait support
\base\ntos\ex – executive object (layered on kernel support)
\base\ntos\ex – executive object (layered on kernel support)
Event.c – Event object Event.c – Event object Mutant.c – Mutex object Mutant.c – Mutex object
Semphore.c – Semaphore object Semphore.c – Semaphore object Timer.c – Timer object
Timer.c – Timer object
\base\ntos\inc\ke.h, ex.h – structure/type definitions
\base\ntos\inc\ke.h, ex.h – structure/type definitions