这个问题是一个标准的、著名的同时性编程问题的集合:一个有限缓冲区和两类线程,它们是生产者和消费者,生产者把产品放入缓冲区,相反消费者便是从缓冲区中拿走产品。
生产者在缓冲区满时必须等待,直到缓冲区有空间才继续生产。消费者在缓冲区空时必须等待,直到缓冲区中有产品才能继续读取。
在这个问题上主要考虑的是:缓冲区满或缓冲区空以及竞争条件。
#include < stdlib.h >
#include < time.h >
#include " pthread.h "
#include " semaphore.h "
#ifndef _OSCONFIG_
#define _OSCONFIG_
#ifdef _WIN32
/*
* OS Win32
* Define SLEEP to the windows.h Sleep
* And we use The POSIX 1003.1-2001 standard: Pthreads-w32 release 2.8.0
* See: http://sourceware.org/pthreads-win32/
* The include file, lib, dll have already included in the project
* Just remember to copy "pthreadVC2.dll" with executable file
*/
#include < windows.h >
#define CLOCK(t) t=clock()
#define SLEEP(millisecond) Sleep(millisecond)
#pragma comment(lib, "pthreadVC2.lib")
#else
/*
* OS Others
* e... Just if it is not win32 we consider it is Linux or Unix(Maybe others, then error will occur...)
* Define SLEEP to the usleep function
*/
#include < sys / time.h >
#include < unistd.h >
timeval a;
#define CLOCK(t) gettimeofday(&a,0),t=(a.tv_sec*1000+a.tv_usec/1000)
#define SLEEP(millisecond) usleep((millisecond)*1000)
#endif
#endif
#ifndef _BUFFER_
#define _BUFFER_
/*
* Define Buffer
* Default Size: 5 and change it if you like
* The buffer is manipulated as a circular queue
* Push item at the last of the buffer
* And pop item at the begin of the buffer
* If it is full or empty, an error will occur
*/
typedef int buffer_item;
#define BUFFER_SIZE 5
buffer_item buffer[BUFFER_SIZE];
int currentSize = 0 ;
int currentIndex = 0 ;
int insert_item(buffer_item item)
{
return currentSize < BUFFER_SIZE
? (buffer[(currentIndex + currentSize ++ ) % BUFFER_SIZE] = item, 1 ) : 0 ;
}
int remove_item(buffer_item * item)
{
return (currentSize && buffer[currentIndex] ==* item)
? ( -- currentSize, currentIndex = (currentIndex + 1 ) % BUFFER_SIZE, 1 ) : 0 ;
}
#endif
// mutex: only one thread can operate the buffer
pthread_mutex_t mutex;
// full: when get the semaphore, consumer can get item from the buffer
sem_t full;
// empty: when get the semaphore, producer can put item to the buffer
sem_t empty;
// threadStart: The start time of the thread
clock_t threadStart;
/*
* Producer
* Produce items and try to put it into the buffer
* If the buffer is full, waiting
* When produced, we output like that: Producer 2 produced 222
* When successfully put, we output: Producer 2 have put product 222 into the buffer after 100 milliseconds
* The milliseconds is the timespan from the producer produced the item
* When the buffer is full but the producer put the item, an error occurred
* (No way it will happen...)
*/
#define PTIMESPANMAX 5000
void * producer( void * params )
{
int id =* ( int * ) params ;
while ( true )
{
SLEEP(rand() % PTIMESPANMAX);
buffer_item rnd = rand();
long begin, end;
CLOCK(begin);
printf( " %ld:\t Producer %d\t produced %d\n " , ( long )(begin - threadStart), id, rnd);
sem_wait( & empty);
pthread_mutex_lock( & mutex);
(CLOCK(end), insert_item(rnd))
? printf( " %ld:\t Producer %d\t have put %d\t after %d\t milliseconds\n " ,end - threadStart, id, rnd, end - begin)
: printf( " %ld:\t Producer %d\t Report Error!\n " , end - threadStart, id);
pthread_mutex_unlock( & mutex);
sem_post( & full);
}
}
/*
* Consumer
* Try to consume items from the buffer
* If the buffer is empty, waiting
* When try to consume, we output like that: Consumer 3 want to consume
* When successfully consumed, we output: Consumer 3 consumed 222 after 100 milliseconds
* The milliseconds is the timespan from the consumer try to consume the item
* When the buffer is empty but the consumer consumed the item, an error occurred
* (No way it will happen...)
*/
#define CTIMESPANMAX 5000
void * consumer( void * params )
{
int id =* ( int * ) params ;
while ( true )
{
SLEEP(rand() % CTIMESPANMAX);
long begin, end;
CLOCK(begin);
printf( " %ld:\t Consumer %d\t want to consume\n " , begin - threadStart, id);
sem_wait( & full);
pthread_mutex_lock( & mutex);
buffer_item item = buffer[currentIndex];
(CLOCK(end), remove_item( & item))
? printf( " %ld:\t Consumer %d\t consumed %d\t after %d\t milliseconds\n " , end - threadStart, id, item, end - begin)
: printf( " %ld:\t Consumer %d\t Report Error!\n " , end - threadStart, id);
pthread_mutex_unlock( & mutex);
sem_post( & empty);
}
}
int main( int argc, char * argv[])
{
srand(time( 0 ));
// Init mutex, full and empty
pthread_mutex_init( & mutex, NULL);
sem_init( & full, 0 , BUFFER_SIZE);
sem_init( & empty, 0 , BUFFER_SIZE);
int i = 0 ;
// e... No item in the buffer now, so full is "full"
for (i = 0 ; i < BUFFER_SIZE; i ++ )
sem_wait( & full);
int sleepTime = 0 ;
int producerCount = 0 ;
int consumerCount = 0 ;
if (argc == 4 ) // get parameters from the args
{
sscanf(argv[ 1 ], " %d " , & sleepTime);
sscanf(argv[ 2 ], " %d " , & producerCount);
sscanf(argv[ 3 ], " %d " , & consumerCount);
}
else // no args? input!
{
printf( " How long to sleep before terminating: " ); scanf( " %d " , & sleepTime);
printf( " The number of producer threads: " ); scanf( " %d " , & producerCount);
printf( " The number of consumer threads: " ); scanf( " %d " , & consumerCount);
}
// Init threadStart
CLOCK(threadStart);
// Create producer threads
for (i = 0 ; i < producerCount; i ++ )
{
pthread_t pid;
pthread_create( & pid, NULL, producer, ( void * ) & i);
SLEEP( 1 );
}
// Create consumer threads
for (i = 0 ; i < consumerCount; i ++ )
{
pthread_t pid;
pthread_create( & pid, NULL, consumer, ( void * ) & i);
SLEEP( 1 );
}
// Just wait and then... end
SLEEP(sleepTime);
printf( " End of time\n " );
return 0 ;
}
这段代码在Windows与Linux下都可以编译通过,主要是判断平台封装了一些特定函数,比如sleep休眠和clock时间函数
Windows下需要Pthread for Win32库 详细的 参考 http://sourceware.org/pthreads-win32/,将pthread.h sched.h semaphore.h 以及pthreadvc2.lib复制到工程目录下(需要修改pthread.h里#include <sched.h>为 #include "sched.h",也可以复制到VC的include和lib目录,这样就不需要修改了)。使用VC编译,将pthreadvc2.dll复制到exe同目录下就可以执行了。
Linux下就比较简单了,直接编译运行:
gcc OsTest2.cpp –c –pthread
gcc OsTest2.o –o OsTest2 –pthread –lstdc++
./OsTest2
恩……整个实验还是比较简单的...