进程机制与并发程序设计-Linux下C实现(二) 生产者与消费者问题
作者:刘寅 08-01-06
一,问题分析:
在学习进程互斥中,有个著名的问题:生产者-消费者问题。这个问题是一个标准的、著名的同时性编程问题的集合:一个有限缓冲区和两类线程,它们是生产者和消费者,生产者把产品放入缓冲区,相反消费者便是从缓冲区中拿走产品。生产者在缓冲区满时必须等待,直到缓冲区有空间才继续生产。消费者在缓冲区空时必须等待,直到缓冲区中有产品才能继续读取。在这个问题上主要考虑的是:缓冲区满或缓冲区空以及竞争条件(race condition)。
二,伪码分析:
empty为缓冲区中空元素的个数,初值为n
flul
为缓冲区中已生产元素的个数,
初值为0
Mutex为对缓冲区互斥访问加的锁
Main()
{
codebegin
Productor();
Customer();
codeend
}
Productor() while(true)
{
P(empty)
p(mutex)
生产产品;
往Buffer [i]中放产 品;
V(mutex)
V(full)
}
Customer():
While(true)
{
P(full)
P(mutex)
从Buffer[J]取产品;
V(mutex)
V(empty)
消费产品
}
三,linux下实现:
在linux readhat 9.0下测试通过
进入pro_cus 文件夹,然后用shell运行”make ”命令即可
Pro_cus文件说明
--const.h 在本项目中使用到的一些常量的定义
1
#ifndef CONST_H
2
#define
CONST_H
3
#define
MaxSize 10
//
栈中最多只有十个元素
4
#define
TRUE 1
5
#define
FALSE 0
6
#define
ERROR 0
7
#define
OVERFLOW -2
8
#define
OK 1
9
#define
MAXSIZE 20
10
#define
MAXLEN 100
//
字符串的最大长度
11
#endif
12

13
--exp1.c 本项目的主程序
1
#include
<
stdio.h
>
2
#include
<
stdlib.h
>
3
#include
<
unistd.h
>
4
#include
<
pthread.h
>
5
#include
<
errno.h
>
6
#include
<
sys
/
ipc.h
>
7
#include
<
semaphore.h
>
8
#include
<
fcntl.h
>
9
#include
"
Queue.h
"
10
#include
"
const.h
"
11
#define
N 5
12
time_t end_time;
13
sem_t mutex,full,empty;
14
int
fd;
15

Queue
*
qt;
/**/
/*缓冲区*/
16
Elemtype p;
17

18
void
consumer(
void
*
arg);
19
void
productor(
void
*
arg);
20

21
int
main(
int
argc,
char
*
argv[])
22

{
23
pthread_t id1,id2;
24
pthread_t mon_th_id;
25
int ret;
26
end_time = time(NULL)+30;
27
qt = InitQueue();
28
p.lNumber = 1000;
29
ret=sem_init(&mutex,0,1); /**//*初使化互斥信号量为1*/
30
ret=sem_init(&empty,0,N); /**//*初使化empty信号量为N*/
31
ret=sem_init(&full,0,0); /**//*初使化full信号量为0*/
32
if(ret!=0)
33
{
34
perror("sem_init");
35
}
36
ret=pthread_create(&id1,NULL,(void *)productor, NULL); /**//*创建两个线程*/
37
if(ret!=0)
38
perror("pthread cread1");
39
ret=pthread_create(&id2,NULL,(void *)consumer, NULL);
40
if(ret!=0)
41
perror("pthread cread2");
42
pthread_join(id1,NULL);
43
pthread_join(id2,NULL);
44
45
exit(0);
46
}
47

/**/
/*生产者线程*/
48
void
productor(
void
*
arg)
49

{
50
int i,nwrite;
51
while(time(NULL) < end_time)
{
52
sem_wait(&empty);// p(empty)
53
sem_wait(&mutex);// p(mutex)
54
if(TRUE==QueueFull(*qt))
55
{
56
//队满
57
printf("Productor:buffer is full ,please try to write later.\n");
58
}
59
else
60
{
61
EnQueue(qt,p);
62
printf("Productor:write [%d] to buffer \n",p.lNumber);
63
p.lNumber++;
64
}
65
66
sem_post(&full);//v(full)
67
sem_post(&mutex);//v(mutex)
68
sleep(1);
69
}
70
}
//
productor
71
72

/**/
/*消费者线程*/
73
void
consumer(
void
*
arg)
74

{
75
int nolock=0;
76
int ret,nread;
77
Elemtype p2;
78
while((time(NULL) < end_time)||(FALSE==(QueueEmpty(*qt))))
79
{
80
sem_wait(&full);//p(full)
81
sem_wait(&mutex);//p(mutex)
82
if(TRUE==QueueEmpty(*qt))
83
{
84
//队空
85
printf("Consumer:the buffer is empty,please try to read later.\n");
86
}
87
else
88
{
89
DeQueue(qt,&p2);
90
printf("Consumer:read [%d] from buffer.\n",p2.lNumber);
91
}
92
sem_post(&empty);//v(empty)
93
sem_post(&mutex);//v(mutex)
94
sleep(2);
95
}/**//*end of while((time(NULL) < end_time)||(FALSE==(QueueEmpty(*qt))))*/
96
}
//
consumer
97
98
--Queue.c 循环队列的实现
1
/**/
/*
2
队列的基本操作函数
3
*/
4
#include
"
stdio.h
"
5
#include
"
malloc.h
"
6
#include
"
const.h
"
7
#include
"
Queue.h
"
8

/**/
/*
9
初使化队列
10
*/
11
Queue
*
InitQueue()
12

{
13
Queue * Q = (Queue *)malloc(sizeof(Queue));
14
15
Q->front = Q->rear = 0;
16
return Q;
17
}
18

19

/**/
/*
20
进队
21
*/
22
int
EnQueue(Queue
*
Q,Elemtype x)
23

{
24
if((Q->rear + 1)%MaxSize==Q->front)/**//* 队满 */
25
return FALSE;
26
else
27
{
28
Q->q[Q->rear] = x;
29
Q->rear = (Q->rear+1)%MaxSize;
30
return TRUE;
31
}
32
}
33

34

/**/
/*
35
出队
36
*/
37
int
DeQueue(Queue
*
Q,Elemtype
*
x)
38

{
39
if(Q->rear==Q->front)/**//*队空*/
40
return FALSE;
41
else
42
{
43
*x = Q->q[Q->front];
44
Q->front = (Q->front+1)%MaxSize;
45
return TRUE;
46
}
47
}
48

49

/**/
/*
50
判断队是否为空,空返回0
51
非空返回 1
52
*/
53
int
QueueEmpty(Queue Q)
54

{
55
if(Q.rear==Q.front)/**//*队空*/
56
return TRUE;
57
else
58
return FALSE;
59
}
60

61

/**/
/*
62
返回队例中的最后的一个元素(原队列还要存在)
63
*/
64
Elemtype Last(Queue
*
Q)
65

{
66
67
Elemtype *prElem = NULL;
68
Queue *prTempQueue;
69
/**//*这个临时队列,把原队列放到里面,当取完最后一
70
个元素后,就把这个队列中的元素放回原来的队列*/
71
prTempQueue = InitQueue();
72
while(QueueEmpty(*Q)==1)
73
{
74
DeQueue(Q,prElem);
75
EnQueue(prTempQueue,*prElem);
76
}
77
while(QueueEmpty(*prTempQueue)==1)
78
{
79
DeQueue(prTempQueue,prElem);
80
EnQueue(Q,*prElem);
81
}
82
return *prElem;
83
}
/**/
/*Last*/
84

85

/**/
/*
86
判断队是否为满,满返回TRUE
87
非满返回FALSE
88
*/
89
int
QueueFull(Queue Q)
90

{
91
if(((Q.rear+1)%MaxSize)==Q.front)/**//*队空*/
92
return TRUE;
93
else
94
return FALSE;
95
}
96
--Queue.h 循环队列的函数说明
1
#ifndef QUEUE_H_LY
2
#define
QUEUE_H_LY
3
#include
"
Typedefine.h
"
4

/**/
/*
5
2007-12-23 10:31:14
6
*/
7

/**/
/*
8
初使化队列信息
9
*/
10
Queue
*
InitQueue();
11

/**/
/*
12
进队(因为没有队满的情况,所以没有返回值)
13
*/
14

15
int
EnQueue(Queue
*
Q,Elemtype x);
16

/**/
/*
17
出队,x为出队的那个结点的数据域
18
返回:1成功/0失败
19
*/
20
int
DeQueue(Queue
*
Q,Elemtype
*
x);
21

/**/
/*
22
判断队空1(不空)/0(为空)
23
*/
24
int
QueueEmpty(Queue Q);
25

/**/
/*
26
统计一个栈链中的元素的个数
27
*/
28
int
QueueCount(Queue
*
HQ);
29

30

/**/
/*
31
判断队是否为满,满返回TRUE
32
非满返回FALSE
33
*/
34
int
QueueFull(Queue Q);
35

36
#endif
37
--Typedefine.h 本项目中用到一些数据结构,详细的请参考代码
Code
1
#ifndef TYPEDEFINE_H
2
#define TYPEDEFINE_H
3
#include "const.h"
4
5
typedef struct/**//*字符串的类型*/
6

{
7
char data[MAXLEN];//数据区
8
int len;//长度,没包括了'\0'的长度,如"abc",长度为3
9
}SString;
10
11
//typedef int Elemtype;
12
typedef struct
13

{
14
SString* strName;//名字
15
long lNumber;//号码
16
}Elemtype;
17
18
/**//*
19
本页面主要是对在程序中使用到的类型做定义
20
如结点类型,数据类型
21
*/
22
23
typedef struct node
24

{
25
//结点的数据域
26
Elemtype data;
27
28
//结点的指针域,存放下一个结点的地址
29
struct node *next;
30
}SNode;
31
32
33
34
/**//*队列的基本结构*/
35
typedef struct
36

{
37
//存放队列元素
38
Elemtype q[MaxSize];
39
40
//头指针
41
int front;
42
43
//尾指针(尾元素的下一个位置)
44
int rear;
45
}Queue;
46
47
/**//*
48
链队列的结构定义
49
typedef struct
50
{
51
SNode *front ,*rear;
52
53
}LQueue;
54
*/
55
56
57
/**//*栈的基本类型定义*/
58
typedef struct st
59

{
60
Elemtype data[MaxSize];
61
int top;
62
}Stack;
63
64
65
66
typedef int BOOL;
67
typedef int Status;
68
69
70
71
#endif
72
源码下载