If only one side of processes crash, the other side of processes do not hang.
来源:互联网 发布:淘宝怎么设置周末收货 编辑:程序博客网 时间:2024/05/21 09:52
Use the shared memory to implement a queue, and producers can use it to transfer data to consumers. If only one side of processes crash, the other side of processes do not hang.
The interface is:
#ifndef PROTOCOL_H_B85C8C91_F359_415D_BE50_73059A34568B#define PROTOCOL_H_B85C8C91_F359_415D_BE50_73059A34568B#ifdef __cplusplusextern "C" {#endifHANDLE InitializeProducers( LPCTSTR ptcSharedName, size_t nItemSize, size_t nMaxItems, size_t nMilliseconds );HANDLE InitializeConsumers( LPCTSTR ptcSharedName, size_t nMilliseconds );BOOL DestroyHandle( HANDLE );/** * Pushes the specified element into this queue, waiting up to the * specified wait time if necessary for space to become available. * * The return value: * TRUE -> The element has been pushed to the queue successfully; * FALSE -> Failed to push the element to the queue. You may call * GetLastError() to get the error code. */BOOL AddItem( HANDLE, const void * data, size_t nBytes, size_t nMilliseconds );/* * Check where there are any consumers. * ONLY producers are allowed to call the function. * * NOTE: in order to make it relyable, the value of the parameter nMilliseconds * should be more than number_of_producers * 2 * 1000. * * The return value: * TRUE -> there are some consumers. * FALSE -> cannot find any consumers during the period of time. */BOOL AreThereAnyConsumers( HANDLE, size_t nMilliseconds );/** * Retrieves and removes the head of this queue, waiting up to the * specified wait time if necessary for an element to become available. * * The return value: * TRUE -> A element has been retrieved from the queue successfully; * FALSE -> Failed to retrieve a element from the queue. You may call * GetLastError() to get the error code. */BOOL TakeItem( HANDLE, void * buffer, size_t nBufferSize, size_t * pNumberOfBytesRead, size_t nMilliseconds );/* * Check where there are any producers. * ONLY consumers are allowed to call the function. * * NOTE: in order to make it reliable, the value of the parameter nMilliseconds * should be more than number_of_consuers * 2 * 1000. * * The return value: * TRUE -> there are some producers. * FALSE -> cannot find any producers during the period of time. */BOOL AreThereAnyProducers( HANDLE, size_t nMilliseconds );BOOL GetRemainingCapacity( HANDLE h, size_t * pNumberOfRemainedItems, size_t * pNumberOfRemainedBytes );#ifdef __cplusplus}#endif#endif //PROTOCOL_H_B85C8C91_F359_415D_BE50_73059A34568B
The implementation is:
#define _WIN32_WINNT 0x400#include "../Protocol.h"#include "../AutoHandle.h"#include <stdio.h>#include <assert.h>#include <process.h>#define MAGIC 427036969namespace{ const UINT_PTR MASK = static_cast<UINT_PTR>( MAGIC ); const DWORD INTERVAL_UNIT = 1000; struct ItemHeader { UINT offset; UINT bytes; }; struct SharedMemoryQueueHeader { UINT total_bytes; UINT offset_of_data; UINT number_of_items; UINT item_size; LONG magic; volatile LONG producer; volatile LONG consumer; volatile UINT begin; volatile UINT end; volatile UINT count_of_items; volatile UINT remained_bytes; volatile UINT offset_of_writting; UINT end_of_offset; UINT padding[3]; ItemHeader items[1]; }; struct MyHandle { UINT_PTR magic; HANDLE hf; HANDLE timer; //HANDLE done; BYTE * pointer_to_first_byte_of_data_space; SharedMemoryQueueHeader * header; HANDLE empty; HANDLE saved; HANDLE mutex; }; inline static UINT prev_position( UINT i, UINT N ) { return ( i + N - 1 )%N; } inline static UINT next_position( UINT i, UINT N ) { return ( i + 1 )%N; } inline unsigned __int64 get_time_in_milliseconds() { return GetTickCount64(); } DWORD wait( HANDLE handle, DWORD dwMilliseconds ) { DWORD dwRtn; for ( DWORD t; ; ) { t = GetTickCount(); __try { dwRtn = WaitForSingleObjectEx( handle, dwMilliseconds, TRUE ); } __except( EXCEPTION_EXECUTE_HANDLER ) { dwRtn = WAIT_FAILED; } if ( dwRtn == WAIT_IO_COMPLETION ) { t = GetTickCount() - t; if ( dwMilliseconds > t ) { dwMilliseconds -= t; } else { dwRtn = WAIT_TIMEOUT; break; } } else { break; } } return dwRtn; } DWORD wait( DWORD nCount, const HANDLE* lpHandles, BOOL bWaitAll, DWORD dwMilliseconds ) { DWORD dwRtn; for ( DWORD t; ; ) { t = GetTickCount(); __try { dwRtn = WaitForMultipleObjectsEx( nCount, lpHandles, bWaitAll, dwMilliseconds, TRUE ); } __except( EXCEPTION_EXECUTE_HANDLER ) { dwRtn = WAIT_FAILED; } if ( dwRtn == WAIT_IO_COMPLETION ) { t = GetTickCount() - t; if ( dwMilliseconds > t ) { dwMilliseconds -= t; } else { dwRtn = WAIT_TIMEOUT; break; } } else { break; } } return dwRtn; } void CALLBACK my_timer_apc_procedure_for_producer( LPVOID lpArg, DWORD, DWORD ) { SharedMemoryQueueHeader * header = reinterpret_cast<SharedMemoryQueueHeader*>( lpArg ); InterlockedExchange( &header->producer, 1 ); } void CALLBACK my_timer_apc_procedure_for_consumer( LPVOID lpArg, DWORD, DWORD ) { SharedMemoryQueueHeader * header = reinterpret_cast<SharedMemoryQueueHeader*>( lpArg ); InterlockedExchange( &header->consumer, 0 ); } HANDLE create_timer( SharedMemoryQueueHeader * header, PTIMERAPCROUTINE pfnCompletionRoutine, LPCTSTR ptcTimerName = NULL ) { HANDLE hTimer = CreateWaitableTimer( NULL, FALSE, ptcTimerName); if ( hTimer != NULL ) { __int64 qwDueTime; LARGE_INTEGER liDueTime; __try { qwDueTime = -1000 * static_cast<__int64>( INTERVAL_UNIT ); liDueTime.LowPart = static_cast<DWORD>( qwDueTime & 0xFFFFFFFF ); liDueTime.HighPart = static_cast<LONG>( qwDueTime >> 32 ); if ( !SetWaitableTimer( hTimer, &liDueTime, INTERVAL_UNIT, pfnCompletionRoutine, header, FALSE // Do not restore a suspended system ) ) { CloseHandle( hTimer ); hTimer = NULL; } } __except( EXCEPTION_EXECUTE_HANDLER ) { CloseHandle( hTimer ); hTimer = NULL; } } return hTimer; }}extern "C" HANDLE InitializeProducers( LPCTSTR ptcSharedName, size_t nItemSize, size_t nMaxItems, size_t nMilliseconds ){ HANDLE return_value = NULL; SYSTEM_INFO si = {0}; GetSystemInfo( &si ); DWORD dwSize = static_cast<DWORD>( ( nItemSize + sizeof( ItemHeader ) ) * nMaxItems + 256 + si.dwPageSize - 1 ); dwSize = dwSize/si.dwPageSize*si.dwPageSize; TCHAR buf[ _MAX_PATH << 1 ]; LONG lMaxItems = static_cast<LONG>( nMaxItems ); _sntprintf_s( buf, _TRUNCATE, _T("%s_SEMAPHORE_SAVED"), ptcSharedName ); util::auto_handle<HANDLE, util::HandleDestructor<HANDLE> > saved( CreateSemaphore( NULL, 0, lMaxItems, buf ) ); _sntprintf_s( buf, _TRUNCATE, _T("%s_SEMAPHORE_EMPTY"), ptcSharedName ); util::auto_handle<HANDLE, util::HandleDestructor<HANDLE> > empty( CreateSemaphore( NULL, lMaxItems, lMaxItems, buf ) ); _sntprintf_s( buf, _TRUNCATE, _T("%s_CRITICAL_SECTION"), ptcSharedName ); util::auto_handle<HANDLE, util::HandleDestructor<HANDLE> > mutex( CreateMutex( NULL, FALSE, buf ) ); bool bNew = true; util::auto_handle<HANDLE, util::HandleDestructor<HANDLE> > hf( CreateFileMapping( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, dwSize, ptcSharedName ) ); if ( GetLastError() == ERROR_ALREADY_EXISTS ) { bNew = false; dwSize = 0; } if ( saved.get() != NULL && empty.get() != NULL && mutex.get() != NULL && hf.get() != NULL ) { MyHandle * pmh = reinterpret_cast<MyHandle*>( malloc( sizeof( MyHandle ) ) ); if ( pmh != NULL ) { util::auto_handle<void *, util::HandleDestructor<const void *, UnmapViewOfFile> > pv( MapViewOfFile( hf.get(), FILE_MAP_WRITE|FILE_MAP_READ, 0, 0, dwSize ) ); SharedMemoryQueueHeader * header = reinterpret_cast<SharedMemoryQueueHeader *>( pv.get() ); util::auto_handle<HANDLE, util::HandleDestructor<HANDLE> > timer( pv != NULL ? create_timer( header, my_timer_apc_procedure_for_producer ) : NULL ); if ( pv.get() != NULL && timer.get() != NULL ) { if ( bNew ) { header->total_bytes = static_cast<UINT>( dwSize ); header->begin = 0; header->end = 0; header->count_of_items = 0; header->number_of_items = static_cast<UINT>( nMaxItems ); header->offset_of_data = static_cast<UINT>( ( reinterpret_cast<BYTE *>( &header->items[nMaxItems] ) ) - static_cast<BYTE*>( pv.get() ) ); header->remained_bytes = header->total_bytes; header->offset_of_writting = 0; header->end_of_offset = dwSize - header->offset_of_data; header->item_size = static_cast<UINT>( nItemSize ); } else { DWORD dwPeriodicTimerInterval = ( static_cast<DWORD>( nMilliseconds ) + INTERVAL_UNIT - 1 ) / INTERVAL_UNIT * INTERVAL_UNIT; for ( ; header->magic != MAGIC && dwPeriodicTimerInterval > INTERVAL_UNIT; dwPeriodicTimerInterval -= INTERVAL_UNIT ) { Sleep( INTERVAL_UNIT ); } } if ( bNew || header->magic == MAGIC ) { pmh->magic = MASK; pmh->hf = hf.detach(); pmh->header = header; pmh->empty = empty.detach(); pmh->saved = saved.detach(); pmh->mutex = mutex.detach(); pmh->timer = timer.detach(); pmh->pointer_to_first_byte_of_data_space = static_cast<BYTE*>( pv.detach() ) + header->offset_of_data; return_value = reinterpret_cast<HANDLE>( reinterpret_cast<UINT_PTR>( pmh ) ^ MASK ); InterlockedExchange( &pmh->header->magic, MAGIC ); InterlockedExchange( &pmh->header->producer, 1 ); ResumeThread( pmh->timer ); } else { free( pmh ); } } else { free( pmh ); } } } return return_value;}extern "C" HANDLE InitializeConsumers( LPCTSTR ptcSharedName, size_t nMilliseconds ){ HANDLE return_value = NULL; TCHAR buf[ _MAX_PATH << 1 ]; _sntprintf_s( buf, _TRUNCATE, _T("%s_SEMAPHORE_SAVED"), ptcSharedName ); util::auto_handle<HANDLE, util::HandleDestructor<HANDLE> > saved( OpenSemaphore( SEMAPHORE_ALL_ACCESS, FALSE, buf ) ); _sntprintf_s( buf, _TRUNCATE, _T("%s_SEMAPHORE_EMPTY"), ptcSharedName ); util::auto_handle<HANDLE, util::HandleDestructor<HANDLE> > empty( OpenSemaphore( SEMAPHORE_ALL_ACCESS, FALSE, buf ) ); _sntprintf_s( buf, _TRUNCATE, _T("%s_CRITICAL_SECTION"), ptcSharedName ); util::auto_handle<HANDLE, util::HandleDestructor<HANDLE> > mutex( OpenMutex( MUTEX_ALL_ACCESS, FALSE, buf ) ); util::auto_handle<HANDLE, util::HandleDestructor<HANDLE> > hf( OpenFileMapping( FILE_MAP_ALL_ACCESS, FALSE, ptcSharedName ) ); if ( saved.get() != NULL && empty.get() != NULL && mutex.get() != NULL && hf.get() != NULL ) { MyHandle * pmh = reinterpret_cast<MyHandle*>( malloc( sizeof( MyHandle ) ) ); if ( pmh != NULL ) { util::auto_handle<void *, util::HandleDestructor<const void *, UnmapViewOfFile> > pv( MapViewOfFile( hf.get(), FILE_MAP_WRITE|FILE_MAP_READ, 0, 0, 0 ) ); SharedMemoryQueueHeader * header = reinterpret_cast<SharedMemoryQueueHeader *>( pv.get() ); util::auto_handle<HANDLE, util::HandleDestructor<HANDLE> > timer( pv.get() != NULL ? create_timer( header, my_timer_apc_procedure_for_consumer ) : NULL ); if ( pv.get() != NULL && timer.get() != NULL ) { for ( DWORD dwPeriodicTimerInterval = ( static_cast<DWORD>( nMilliseconds ) + INTERVAL_UNIT - 1 ) / INTERVAL_UNIT * INTERVAL_UNIT; header->magic != MAGIC && dwPeriodicTimerInterval > INTERVAL_UNIT; dwPeriodicTimerInterval -= INTERVAL_UNIT ) { Sleep( INTERVAL_UNIT ); } if ( header->magic == MAGIC ) { pmh->magic = MASK; pmh->hf = hf.detach(); pmh->header = header; pmh->empty = empty.detach(); pmh->saved = saved.detach(); pmh->mutex = mutex.detach(); pmh->timer = timer.detach(); pmh->pointer_to_first_byte_of_data_space = static_cast<BYTE*>( pv.detach() ) + header->offset_of_data; return_value = reinterpret_cast<HANDLE>( reinterpret_cast<UINT_PTR>( pmh ) ^ MASK ); InterlockedExchange( &pmh->header->magic, MAGIC ); InterlockedExchange( &pmh->header->consumer, 0 ); ResumeThread( pmh->timer ); } else { free( pmh ); } } else { free( pmh ); } } } return return_value;}extern "C" BOOL DestroyHandle( HANDLE h ){ BOOL bSuccessful = FALSE; MyHandle * pmh = reinterpret_cast<MyHandle*>( reinterpret_cast<UINT_PTR>( h ) ^ MASK ); if ( pmh != NULL && pmh->magic == MASK ) { UnmapViewOfFile( pmh->header ); CloseHandle( pmh->timer ); CloseHandle( pmh->saved ); CloseHandle( pmh->empty ); CloseHandle( pmh->mutex ); CloseHandle( pmh->hf ); pmh->magic = 0; free( pmh ); bSuccessful = TRUE; } return bSuccessful;}extern "C" BOOL AddItem( HANDLE h, const void * data, size_t nBytes, size_t dwMilliseconds ){ BOOL bSuccessful = FALSE; MyHandle * pmh = reinterpret_cast<MyHandle*>( reinterpret_cast<UINT_PTR>( h ) ^ MASK ); if ( pmh != NULL && pmh->magic == MASK && data != NULL && nBytes != 0 && nBytes <= pmh->header->remained_bytes ) { DWORD dwRtn = wait( pmh->empty, static_cast<DWORD>( dwMilliseconds ) ); if ( dwRtn == WAIT_OBJECT_0 ) { dwRtn = wait( pmh->mutex, static_cast<DWORD>( dwMilliseconds ) ); if ( dwRtn == WAIT_OBJECT_0 ) { SharedMemoryQueueHeader * header = pmh->header; BYTE * pointer_to_first_byte = pmh->pointer_to_first_byte_of_data_space; if ( nBytes <= header->remained_bytes ) { header->items[ header->end ].bytes = static_cast<UINT>( nBytes ); header->items[ header->end ].offset = header->offset_of_writting; header->remained_bytes -= static_cast<UINT>( nBytes ); UINT first_part = header->end_of_offset - header->offset_of_writting; if ( first_part >= nBytes ) { memcpy( pointer_to_first_byte + header->offset_of_writting, data, nBytes ); header->offset_of_writting += static_cast<UINT>( nBytes ); if ( first_part == nBytes ) { header->offset_of_writting = 0; } } else { const BYTE * pbInput = static_cast<const BYTE *>( data ); memcpy( pointer_to_first_byte + header->offset_of_writting, pbInput, first_part ); nBytes -= first_part; memcpy( pointer_to_first_byte, pbInput + first_part, nBytes ); header->offset_of_writting = static_cast<UINT>( nBytes ); } header->end = next_position( header->end, header->number_of_items ); ++header->count_of_items; ReleaseMutex( pmh->mutex ); bSuccessful = TRUE; if ( !ReleaseSemaphore( pmh->saved, 1, NULL ) ) { assert( false && "CANNOT handle the kind of error" ); } } else { ReleaseMutex( pmh->mutex ); ReleaseSemaphore( pmh->empty, 1, NULL ); SetLastError( ERROR_DESTINATION_ELEMENT_FULL ); } } else { ReleaseSemaphore( pmh->empty, 1, NULL ); SetLastError( ERROR_TIMEOUT ); } } else { SetLastError( ERROR_TIMEOUT ); } } else { if ( nBytes <= pmh->header->remained_bytes ) { SetLastError( ERROR_INVALID_PARAMETER ); } else { SetLastError( ERROR_DESTINATION_ELEMENT_FULL ); } } return bSuccessful;}#if ( defined( _DEBUG ) || defined( DEBUG ) || defined( DBG ) )bool VerifyString( char * buffer, size_t size ){ bool bSuccessful = false; char * begin = buffer; char * ps = strchr( buffer, ' ' ); if ( ps != NULL ) { *ps = 0; for ( char * pi = buffer; *pi != 0; ++pi ) { assert( isdigit( *pi ) ); } size_t n = strtoul( buffer, NULL, 10 ); *ps++ = ' '; char c = 'a' + static_cast<char>( n%26 ); bSuccessful = true; for ( char i = 'a'; i <= c; ++i, ++ps ) { if ( ps[0] != c ) { assert( false ); bSuccessful = false; break; } } } else { assert( false ); } return bSuccessful;}#endifextern "C" BOOL TakeItem( HANDLE h, void * buffer, size_t nBufferSize, size_t * pNumberOfBytesRead, size_t dwMilliseconds ){ BOOL bSuccessful = FALSE; MyHandle * pmh = reinterpret_cast<MyHandle*>( reinterpret_cast<UINT_PTR>( h ) ^ MASK ); if ( pmh != NULL && pmh->magic == MASK && buffer != NULL && nBufferSize != 0 && pNumberOfBytesRead != NULL ) { DWORD dwRtn = wait( pmh->saved, static_cast<DWORD>( dwMilliseconds ) ); if ( dwRtn == WAIT_OBJECT_0 ) { dwRtn = wait( pmh->mutex, static_cast<DWORD>( dwMilliseconds ) ); if ( dwRtn == WAIT_OBJECT_0 ) { SharedMemoryQueueHeader * header = pmh->header; BYTE * pointer_to_first_byte = pmh->pointer_to_first_byte_of_data_space; if ( header->items[ header->begin ].bytes <= nBufferSize ) { size_t numberOfBytesRead = header->items[ header->begin ].bytes; assert( numberOfBytesRead <= header->total_bytes - header->remained_bytes ); *pNumberOfBytesRead = numberOfBytesRead; header->remained_bytes += static_cast<UINT>( numberOfBytesRead ); UINT offset_of_reading = header->items[ header->begin ].offset; if ( ( offset_of_reading + numberOfBytesRead ) <= header->end_of_offset ) { memcpy( buffer, pointer_to_first_byte + offset_of_reading, numberOfBytesRead ); assert( static_cast<char*>( buffer )[numberOfBytesRead - 1] == 0 ); assert( VerifyString( static_cast<char*>( buffer ), numberOfBytesRead ) ); } else { BYTE * pbOutput = static_cast<BYTE*>( buffer ); size_t first_part = header->end_of_offset - offset_of_reading; memcpy( pbOutput, pointer_to_first_byte + offset_of_reading, first_part ); numberOfBytesRead -= first_part; memcpy( pbOutput + first_part, pointer_to_first_byte, numberOfBytesRead ); } header->begin = next_position( header->begin, header->number_of_items ); --header->count_of_items; ReleaseMutex( pmh->mutex ); bSuccessful = TRUE; if ( !ReleaseSemaphore( pmh->empty, 1, NULL ) ) { assert( false && "CANNOT handle the kind of error" ); } } else { ReleaseMutex( pmh->mutex ); ReleaseSemaphore( pmh->saved, 1, NULL ); SetLastError( ERROR_INSUFFICIENT_BUFFER ); } } else { ReleaseSemaphore( pmh->saved, 1, NULL ); SetLastError( ERROR_TIMEOUT ); } } else { SetLastError( ERROR_TIMEOUT ); } } else { SetLastError( ERROR_INVALID_PARAMETER ); } return bSuccessful;}extern "C" BOOL AreThereAnyConsumers( HANDLE h, size_t dwMilliseconds ){ BOOL bExisted = TRUE; MyHandle * pmh = reinterpret_cast<MyHandle*>( reinterpret_cast<UINT_PTR>( h ) ^ MASK ); if ( pmh != NULL && pmh->magic == MASK ) { bExisted = FALSE; InterlockedExchange( &pmh->header->consumer, 1 ); for ( dwMilliseconds = ( dwMilliseconds + INTERVAL_UNIT - 1 )/INTERVAL_UNIT*INTERVAL_UNIT; dwMilliseconds != 0; dwMilliseconds -= INTERVAL_UNIT ) { if ( InterlockedCompareExchange( &pmh->header->consumer, 0, 0 ) == 0 ) { bExisted = TRUE; break; } else { Sleep( INTERVAL_UNIT ); } } } return bExisted;}extern "C" BOOL AreThereAnyProducers( HANDLE h, size_t dwMilliseconds ){ BOOL bExisted = TRUE; MyHandle * pmh = reinterpret_cast<MyHandle*>( reinterpret_cast<UINT_PTR>( h ) ^ MASK ); if ( pmh != NULL && pmh->magic == MASK ) { bExisted = FALSE; InterlockedExchange( &pmh->header->producer, 0 ); for ( dwMilliseconds = ( dwMilliseconds + INTERVAL_UNIT - 1 )/INTERVAL_UNIT*INTERVAL_UNIT; dwMilliseconds != 0; dwMilliseconds -= INTERVAL_UNIT ) { if ( InterlockedCompareExchange( &pmh->header->producer, 1, 1 ) == 1 ) { bExisted = TRUE; break; } else { Sleep( INTERVAL_UNIT ); } } } return bExisted;}extern "C" BOOL GetRemainingCapacity( HANDLE h, size_t * pNumberOfItems, size_t * pNumberOfBytes ){ BOOL bSuccessful = FALSE; MyHandle * pmh = reinterpret_cast<MyHandle*>( reinterpret_cast<UINT_PTR>( h ) ^ MASK ); if ( pmh != NULL && pmh->magic == MASK && pNumberOfItems != NULL && pNumberOfBytes != NULL ) { if ( WaitForSingleObject( pmh->mutex, 0 ) == WAIT_OBJECT_0 ) { *pNumberOfItems = pmh->header->number_of_items - pmh->header->count_of_items; *pNumberOfBytes = pmh->header->total_bytes - pmh->header->remained_bytes; bSuccessful = TRUE; } } return bSuccessful;}
The test programs are:
Producer:
#include "../Protocol.h"#include <openssl/rand.h>#include <vector>#include <stdlib.h>#include <stdio.h>#include <assert.h>extern "C" int CN_base64Encode( const void * data, size_t nSize, char * buf );inline size_t random( size_t distance ){ union { size_t n; BYTE ab[ sizeof(size_t) ]; }; RAND_bytes( ab, sizeof( ab ) ); n = static_cast<size_t>( static_cast<double>( rand() * n ) / static_cast<double>( RAND_MAX + 1 ) ); return n % distance;}size_t CreateRandomString( size_t index, char * out, size_t size ){ size_t n = random( size ); if ( n == 0 ) { n = size/2; } std::vector<unsigned char> buffer( n ); std::vector<char> output( ( ( n + 2 ) / 3 ) * 4 + 1 ); RAND_bytes( &buffer[0], static_cast<int>( n ) ); CN_base64Encode( &buffer[0], n, &output[0] ); size_t n1 = strlen( &output[0] ); size_t n2 = size - n1 - 1; if ( n2 >= n1 ) { n2 = n1; } else { output[ n2 ] = 0; n2 = strlen( &output[0] ); } int n3 = _snprintf_s( out, size, _TRUNCATE, "%8u <%3u> %s", index, n2, &output[0] ); return static_cast<size_t>( n3 );}#if ( defined( _DEBUG ) || defined( DEBUG ) || defined( DBG ) )size_t CreateString( size_t index, char * out, size_t size ){ assert( out != NULL && size >= 80 ); char * begin = out; char c = 'a' + static_cast<char>( index%26 ); _snprintf_s( out, size, _TRUNCATE, "%u ", index ); out += strlen( out ); for ( char i = 'a'; i <= c; ++i ) { *out++ = c; } *out++ = 0; return out - begin;}#endifint _tmain( int argc, TCHAR * argv[] ){ int error_code = -1; if ( argc >= 2 ) { LPCTSTR ptcSharedName = argv[1]; size_t nWaitingMilliseconds = 5 * 60 * 1000; // five minutes; size_t nItemSize = DEFAULT_ITEM_SIZE; size_t nMaxItems = DEFAULT_NUMBER_OF_ITEMS; if ( argc >= 3 ) { nWaitingMilliseconds = _tcstoul( argv[2], NULL, 10 ); nWaitingMilliseconds *= 1000; } if ( argc >= 4 ) { nItemSize = _tcstoul( argv[3], NULL, 10 ); } if ( argc >= 5 ) { nMaxItems = _tcstoul( argv[4], NULL, 10 ); } HANDLE h = InitializeProducers( ptcSharedName, nItemSize, nMaxItems, nWaitingMilliseconds ); if ( h != NULL ) { try { error_code = 0; #if ( defined( _DEBUG ) || defined( DEBUG ) || defined( DBG ) ) std::vector<char> buffer( nItemSize ); for ( size_t nData, i = 0; i < 100000000; ++i ) { nData = CreateString( i, &buffer[0], buffer.size() ); if ( AddItem( h, &buffer[0], nData, 2 * 1000 ) ) { fprintf( stdout, "%s\n", &buffer[0] ); } else { if ( !AreThereAnyConsumers( h, nWaitingMilliseconds ) ) { fprintf( stdout, "No consumers, exit...\n" ); break; } } } #else std::vector<char> buffer( nItemSize ); for ( size_t nData, i = 1; i < 100000000; ++i ) { nData = CreateRandomString( i, &buffer[0], nItemSize ); if ( AddItem( h, &buffer[0], nData, 2 * 1000 ) ) { fprintf( stdout, "%s\n", &buffer[0] ); } else { DWORD dwErrorCode = GetLastError(); switch ( dwErrorCode ) { case ERROR_INVALID_PARAMETER: case ERROR_DESTINATION_ELEMENT_FULL: --i; continue; } if ( !AreThereAnyConsumers( h, nWaitingMilliseconds ) ) { fprintf( stdout, "No consumers, exit...\n" ); break; } } } #endif } catch ( std::exception & e ) { fprintf( stderr, "Exception: %s\n", e.what() ); } DestroyHandle( h ); } } else { _ftprintf( stderr, _T("Usage: %s <shared name> [<waiting seconds>] [<item size>] [<number of items>]\n"), argv[0] ); } return error_code;}
Consumer:
#include "../Protocol.h"#include <vector>#include <assert.h>#include <stdlib.h>#include <stdio.h>int _tmain( int argc, TCHAR * argv[] ){ int error_code = -1; if ( argc >= 2 ) { LPCTSTR ptcSharedName = argv[1]; size_t nWaitingMilliseconds = 5 * 60 * 1000; // five minutes; if ( argc >= 3 ) { nWaitingMilliseconds = _tcstoul( argv[2], NULL, 10 ); nWaitingMilliseconds *= 1000; } HANDLE h = InitializeConsumers( ptcSharedName, nWaitingMilliseconds ); if ( h != NULL ) { try { error_code = 0; std::vector<char> buffer( 4096 ); buffer.back() = 0; for ( size_t nNumberOfBytesRead = 0; ; nNumberOfBytesRead = 0 ) { if ( TakeItem( h, &buffer[0], buffer.size() - 1, &nNumberOfBytesRead, 2 * 1000 ) ) { buffer[nNumberOfBytesRead] = 0; fprintf( stdout, "%s\n", &buffer[0] ); } else { DWORD dwErrorCode = GetLastError(); switch ( dwErrorCode ) { case ERROR_INVALID_PARAMETER: case ERROR_INSUFFICIENT_BUFFER: buffer.resize( buffer.size() * 2 ); continue; } if ( !AreThereAnyProducers( h, nWaitingMilliseconds ) ) { fprintf( stdout, "No producers, exit...\n" ); break; } } } } catch ( std::exception & e ) { fprintf( stderr, "Exception: %s\n", e.what() ); } DestroyHandle( h ); } } else { _ftprintf( stderr, _T("Usage: %s <shared name> [<waiting seconds>]\n"), argv[0] ); } return error_code;}
- If only one side of processes crash, the other side of processes do not hang.
- The Other Side of Diversity
- Assume the coasting is an infinite straight line. Land is in one side of coasting, sea in the other.
- Detection of the hidden processes
- Detection of the hidden processes
- The lists of TASK_RUNNING processes 1
- The lists of TASK_RUNNING processes 2
- Running Multiple Versions of the Framework Side-by-Side
- The near side of the pie.
- 105. Courtesy on one side only lasts not long. 来而不往非礼也
- Communications of Processes and Threads
- Processes of IIS trouble shooting
- An overview of Linux processes
- LINUX AND THE MAXIMUM NUMBER OF PROCESSES (THREADS)
- 16.Note the following functionalities of various background processes:
- 17.Note the functionalities of various background processes:
- [已解决]In the case of corrupt Gradle processes
- C#中事件的委托的注意事项(can only appear on the left hand side of += or -=)
- iphone开发资源汇总
- ruby中的多态
- 不用if,?:,等判断语句获得两数之中较大的或较小的数
- 精益开发实战:用看板管理大型项目
- Android Drawable来加载网络上的图片
- If only one side of processes crash, the other side of processes do not hang.
- Install Shield 的事件 函数
- 二十二、应用双重锁定检查于单例模式中的问题
- 关于linux ftp配置权限
- 使用fflush清空缓冲区
- mahout在hadoop下安装与测试过程
- 用分数形式精确表达有理数和循环无理数
- java监听器
- 将从数据库中得到的数据,导出到excel表中(得到的数据使用的List泛型)