生产者与消费者

1、生产者与消费者问题

  空间满:生产者不能生产数据;

  空间空:消费者不能取出数据;

  在这种模型下,将会有(生产者:消费者)为:一对一、一对多、多对一、多对多。

  为了简化问题,在这里就只实现一个生产者和一个消费者的问题。

模型如下

生产者与消费者

注意:

  (1)、线程阻塞时,用条件变量来解决。唤醒并运行其后的语句是在遇到阻塞之后;

  (2)、临界区模式;

  pthread_mutex_lock(&mutex);
  //临界区
  pthread_cond_wait(&cond, &mutex); //该函数将自动解锁,此处将会发生阻塞。

  ......

  pthread_mutex_unlock(&mutex);

  (3)、本题还可以采用双缓冲区;

2、代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
#include<pthread.h>
 
#define BUF_SIZE    8   //一个开辟8个数组元素空间
#define MAX_NUM     20   //将一共产生20个数据
 
struct PC{   //生产者与消费者结构体
    pthread_mutex_t mutex;  //互斥量
    pthread_cond_t noempty;  //条件变量,数组不空
    pthread_cond_t nofull;   //条件变量,数组不满
    int buf[BUF_SIZE];  //开辟空间
    int nput;  //数组下标
    int nval;  //要存放的数据
    int size;  //统计当前数组空间大小
}shared = {PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, PTHREAD_COND_INITIALIZER};
 
void* producer(void *arg){
    for(;;){
        pthread_mutex_lock(&shared.mutex);
        if(shared.nval > MAX_NUM){
            pthread_mutex_unlock(&shared.mutex);
            break;
        }
        shared.buf[shared.nput] = shared.nval;
        shared.nput++;
        shared.nval++;
        shared.size++;
 
        if(shared.nput >= BUF_SIZE){
            shared.nput = 0;  //下标始终在0-7
        }
        if(shared.size >= BUF_SIZE){ 
            pthread_cond_wait(&shared.nofull, &shared.mutex);
        }else{
            pthread_cond_signal(&shared.noempty);
        }
        pthread_mutex_unlock(&shared.mutex);
    }
}
 
void *customer(void *arg){
    int value;
    int i = 0;
    for(;;){
        pthread_mutex_lock(&shared.mutex);
        value = shared.buf[i];
        i++;
        printf("value = %d\n", value);   
        if(value >= MAX_NUM){
            pthread_mutex_unlock(&shared.mutex);
            break;
        }
        sleep(1);
 
        if(i >= BUF_SIZE){
            i = 0;
        }
        shared.size--;
        if(shared.size == 0){
            pthread_cond_wait(&shared.noempty, &shared.mutex);
        }else{
            pthread_cond_signal(&shared.nofull);
        }
 
        pthread_mutex_unlock(&shared.mutex);
    }
}
 
void initPc(void){  //对结构体成员初始化
    memset(shared.buf, 0, BUF_SIZE);   
    shared.nput = 0;  //下标从0开始
    shared.nval = 1;  //存放的数据从1开始
    shared.size = 0;  //数组空间大小为0
}
 
int main(void){
    initPc();
    pthread_t pid, cid;
    pthread_create(&pid, NULL, producer, NULL);
    pthread_create(&cid, NULL, customer, NULL);
 
    pthread_join(pid, NULL);
    pthread_join(cid, NULL);
 
    return 0;
}

运行结果

生产者与消费者

  对以上的代码模式解读:首先是生产者生产,在空间满了之后,阻塞等待,此时,消费者在读取数据,等到读取为空的时候,唤醒生产者生产,最后,在生产完了的时候,消费者读取完成,将一起退出for循环。

这里的同步就是利用了锁机制完成的(通过互斥量和条件变量)。