现在的位置: 首页 > 综合 > 正文

操作系统实验 生产者与消费者问题

2013年02月05日 ⁄ 综合 ⁄ 共 5035字 ⁄ 字号 评论关闭

  这个问题是一个标准的、著名的同时性编程问题的集合:一个有限缓冲区和两类线程,它们是生产者和消费者,生产者把产品放入缓冲区,相反消费者便是从缓冲区中拿走产品。

  生产者在缓冲区满时必须等待,直到缓冲区有空间才继续生产。消费者在缓冲区空时必须等待,直到缓冲区中有产品才能继续读取。

  在这个问题上主要考虑的是:缓冲区满或缓冲区空以及竞争条件。

 

#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

 

  恩……整个实验还是比较简单的...

 

抱歉!评论已关闭.