这个问题是一个标准的、著名的同时性编程问题的集合:一个有限缓冲区和两类线程,它们是生产者和消费者,生产者把产品放入缓冲区,相反消费者便是从缓冲区中拿走产品。
生产者在缓冲区满时必须等待,直到缓冲区有空间才继续生产。消费者在缓冲区空时必须等待,直到缓冲区中有产品才能继续读取。
在这个问题上主要考虑的是:缓冲区满或缓冲区空以及竞争条件。
#include <stdio.h>
#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
恩……整个实验还是比较简单的...
Author: CriusWuBlog: http://kingpro.cnblogs.comContact: kingpro@live.cn
This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.
This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.