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


原创粉丝点击