程序设计中经常用到缓冲队列,多个写入线程,多个读取线程,同时操作一个缓冲队列,需要信号量和互斥量等进行同步。
#pragma once
#define TVUP_API
#ifdef _WIN32
#include <windows.h>
typedef HANDLE ThreadHandle;
typedef HANDLE MutexHandle;
typedef HANDLE Semaphore;
typedef struct
{
HANDLE handle;
} Event;
#else /* not _WIN32 */
#include <pthread.h>
#include <semaphore.h>
typedef pthread_t ThreadHandle;
typedef pthread_mutex_t MutexHandle;
typedef pthread_cond_t CondHandle;
typedef sem_t Semaphore;
typedef struct
{
MutexHandle mutex;
CondHandle cond;
int state;
} Event;
#endif /* not _WIN32 */
typedef void * (* ThreadFunction) (void *);
TVUP_API
int dfsThreadCreate( ThreadHandle *pThread, ThreadFunction func, void *pArg );
TVUP_API
int dfsThreadJoin( ThreadHandle thread );
TVUP_API
int dfsThreadMutexInit( MutexHandle *pMutex );
TVUP_API
int dfsThreadMutexDestroy( MutexHandle *pMutex );
TVUP_API
int dfsThreadMutexLock( MutexHandle *pMutex );
TVUP_API
int dfsThreadMutexUnlock( MutexHandle *pMutex );
TVUP_API
int dfsEventInit( Event *pEvent, int state );
TVUP_API
int dfsEventSet( Event *pEvent );
TVUP_API
int dfsEventWait( Event *pEvent, int timeoutUSecs );
TVUP_API
void dfsEventDestroy( Event *pEvent );
TVUP_API
int dfsSemInit( Semaphore * pSem, int initVal);
TVUP_API
int dfsSemSet( Semaphore * pSem );
TVUP_API
int dfsSemWait( Semaphore * pSem, int timeoutMills);
TVUP_API
int dfsSemDestroy( Semaphore * pSem );
#include <list>
typedef void * DataT;
class CRWBuffer
{
public:
enum {MaxBufferLength = 100000,};
public:
CRWBuffer(int nMaxBufLen);
virtual ~CRWBuffer(void);
int ReadBuf( DataT * pBuf);
int WriteBuf(const DataT * pBuf);
int WaitForReadable(int timeoutMSec);
int WaitForWritable(int timeoutMSec);
public:
std::list<DataT> m_Buflist;
Semaphore m_semReadable;
Semaphore m_semWritable;
MutexHandle m_Mutex;
};
#include "RWBuffer.h"
CRWBuffer::CRWBuffer(int nMaxBufLen)
{
dfsThreadMutexInit(&m_Mutex);
dfsSemInit(&m_semReadable, 0);
dfsSemInit(&m_semWritable, nMaxBufLen);
}
CRWBuffer::~CRWBuffer(void)
{
dfsSemDestroy(&m_semWritable);
dfsSemDestroy(&m_semReadable);
dfsThreadMutexDestroy(&m_Mutex);
}
int CRWBuffer::WaitForReadable(int timeoutMSec)
{
return dfsSemWait(&m_semReadable, timeoutMSec);
}
int CRWBuffer::WaitForWritable(int timeoutMSec)
{
return dfsSemWait(&m_semWritable, timeoutMSec);
}
int CRWBuffer::ReadBuf(DataT * pBuf)
{
dfsThreadMutexLock(&m_Mutex);
*pBuf = m_Buflist.front();
m_Buflist.pop_front();
dfsThreadMutexUnlock(&m_Mutex);
dfsSemSet(&m_semWritable);
return 0;
}
int CRWBuffer::WriteBuf(const DataT * pBuf)
{
dfsThreadMutexLock(&m_Mutex);
m_Buflist.push_back(*pBuf);
dfsThreadMutexUnlock(&m_Mutex);
dfsSemSet(&m_semReadable);
return 0;
}
#ifdef WIN32
int dfsThreadCreate( ThreadHandle *pThread, ThreadFunction func, void *pArg )
{
*pThread = CreateThread( 0, 0, (LPTHREAD_START_ROUTINE)func, pArg, 0, 0 );
if ( *pThread == 0 )
return 1;
return 0;
}
int dfsThreadJoin( ThreadHandle thread )
{
WaitForSingleObject( thread, INFINITE );
CloseHandle(thread);
return 0;
}
int dfsThreadMutexInit( MutexHandle *pMutex )
{
BOOL bInitialOwner = FALSE;
LPCTSTR lpName = 0;
*pMutex = CreateMutex( 0, bInitialOwner, lpName );
if ( *pMutex == 0 )
return 1;
return 0;
}
int dfsThreadMutexDestroy( MutexHandle *pMutex )
{
CloseHandle( pMutex );
return 0;
}
int dfsThreadMutexLock( MutexHandle *pMutex )
{
if ( WaitForSingleObject( *pMutex, INFINITE ) )
return 1;
return 0;
}
int dfsThreadMutexUnlock( MutexHandle *pMutex )
{
if ( !ReleaseMutex( *pMutex ) )
return 1;
return 0;
}
int dfsEventInit( Event *pEvent, int state )
{
pEvent->handle = CreateEvent( NULL, FALSE, state ? TRUE : FALSE, NULL );
if ( pEvent->handle == 0 )
return 1;
return 0;
}
int dfsEventSet( Event *pEvent )
{
BOOL retVal;
retVal = SetEvent( pEvent->handle );
if ( !retVal )
return 1;
return 0;
}
int dfsEventWait( Event *pEvent, int timeoutMSecs )
{
DWORD retVal = WaitForSingleObject( pEvent->handle, timeoutMSecs );
if ( retVal != WAIT_OBJECT_0 )
return 0;
return 1;
}
void dfsEventDestroy( Event *pEvent )
{
CloseHandle( pEvent->handle );
}
int dfsSemInit( Semaphore * pSem , int initVal)
{
*pSem = CreateSemaphoreA(NULL, initVal, 100000, NULL);
return 0;
}
int dfsSemSet( Semaphore * pSem )
{
if (!ReleaseSemaphore(*pSem, 1, NULL))
return 1;
return 0;
}
int dfsSemWait( Semaphore * pSem, int timeoutMills)
{
int rc = WaitForSingleObject(*pSem, timeoutMills);
if (rc != WAIT_OBJECT_0)
return 1;
return 0;
}
int dfsSemDestroy( Semaphore * pSem )
{
if (!CloseHandle(*pSem))
return 1;
return 0;
}
#else
int dfsThreadCreate( ThreadHandle *pThread, ThreadFunction func, void *pArg )
{
return pthread_create( pThread, 0, func, pArg );
}
int dfsThreadJoin( ThreadHandle thread )
{
return pthread_join( thread, NULL );
}
int dfsThreadMutexInit( MutexHandle *pMutex )
{
return pthread_mutex_init( pMutex, NULL );
}
int dfsThreadMutexDestroy( MutexHandle *pMutex )
{
return pthread_mutex_destroy( pMutex );
}
int dfsThreadMutexLock( MutexHandle *pMutex )
{
return pthread_mutex_lock( pMutex );
}
int dfsThreadMutexUnlock( MutexHandle *pMutex )
{
return pthread_mutex_unlock( pMutex );
}
int dfsEventInit( Event *pEvent, int state )
{
pthread_mutex_init( &(pEvent->mutex), NULL );
pthread_cond_init( &(pEvent->cond), NULL );
pEvent->state = state;
return 0;
}
int dfsEventSet( Event *pEvent )
{
pthread_mutex_lock( &(pEvent->mutex) );
if ( !(pEvent->state) )
{
pEvent->state = 1;
pthread_cond_signal( &(pEvent->cond) );
}
pthread_mutex_unlock( &(pEvent->mutex) );
return 0;
}
int dfsEventWait( Event *pEvent, int timeoutMSecs )
{
int retVal = 0; /* (if the event's already set, we'll return without making any calls) */
struct timeval curTime;
struct timespec absTimeout;
pthread_mutex_lock( &(pEvent->mutex) );
if ( timeoutMSecs <= 0 )
{
retVal = 0;
while ( !(pEvent->state) && (retVal == 0) )
retVal = pthread_cond_wait( &(pEvent->cond), &(pEvent->mutex) );
pEvent->state = 0; /* auto-reset */
}
else
{
gettimeofday( &curTime, NULL );
curTime.tv_sec += timeoutMSecs / 1000;
curTime.tv_usec += (timeoutMSecs % 1000) * 1000;
if ( curTime.tv_usec >= 1000000 )
{
curTime.tv_usec -= 1000000;
curTime.tv_sec += 1;
}
absTimeout.tv_sec = curTime.tv_sec;
absTimeout.tv_nsec = curTime.tv_usec * 1000;
retVal = 0;
while ( !(pEvent->state) && (retVal == 0) )
retVal = pthread_cond_timedwait( &(pEvent->cond), &(pEvent->mutex), &absTimeout );
pEvent->state = 0; /* auto-reset */
}
pthread_mutex_unlock(&(pEvent->mutex) );
/* Coerce the expeted DFPort "error" into a DFStream "error".
*/
if ( retVal == ETIMEDOUT )
retVal = 1;
return retVal;
}
void dfsEventDestroy( Event *pEvent )
{
pthread_mutex_destroy( &(pEvent->mutex) );
pthread_cond_destroy( &(pEvent->cond) );
}
int dfsSemInit( Semaphore * pSem , int initVal)
{
sem_init(pSem, 0, initVal);
return 0;
}
int dfsSemSet( Semaphore * pSem )
{
sem_post(pSem);
return 0;
}
int dfsSemWait( Semaphore * pSem, int timeoutMills)
{
struct timespec interval = {time(NULL), timeoutMills * 1000000};
int rc = sem_timedwait(pSem, &interval);
if (rc == 0)
return 0;
if (rc == -1 && errno == ETIMEDOUT)
return 1;
return errno;
}
int dfsSemDestroy( Semaphore * pSem )
{
sem_destroy(pSem);
return 0;
}
#endif
#include "RWBuffer.h"
void * ReadFunction(void * args)
{
CRWBuffer * pBuffer = (CRWBuffer *)args;
while (1)
{
if (WAIT_OBJECT_0 == pBuffer->WaitForReadable(1000))
{
DataT data;
pBuffer->ReadBuf(&data);
Sleep(2000);
}
else
{
printf("Wait for readable\n");
}
}
}
void * WriteFunction(void * args)
{
CRWBuffer * pBuffer = (CRWBuffer *)args;
while(1)
{
if (WAIT_OBJECT_0 == pBuffer->WaitForWritable(1000))
{
DataT data;
pBuffer->WriteBuf(&data);
Sleep(10);
}
else
{
printf("Wait for writable\n");
}
}
}
int main(int argc, char * argv [])
{
CRWBuffer * pBuffer = new CRWBuffer(1000);
ThreadHandle t1, t2, t3;
dfsThreadCreate(&t1, ReadFunction, pBuffer);
dfsThreadCreate(&t2, ReadFunction, pBuffer);
dfsThreadCreate(&t3, WriteFunction, pBuffer);
getchar();
return 0;
}