诺亚方舟

沉淀

使用条件变量信号量实现生产者消费者实例

贴出实例前首先介绍多线程编程中需要使用到的几个系统函数。

1
2
int pthread_mutex_lock(pthread_mutex_t *mutex)
int pthread_mutex_unlock(pthread_mutex_t *mutex)

1、将互斥量锁住,获取不到时将线程阻塞住,按照锁的特性进行相应等待响应动作,当获取到互斥锁时恢复线程。

1
2
int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex)
int pthread_cond_signal(pthread_cond_t *cond)

2、条件变量,条件变量的使用是利用全局变量互斥量来保驾护航,也就是说在调用条件变量等待前需要先获取到互斥量,保证条件变量的调用等待有先后顺序,调用者把线程放到等待条件的线程列表上,然后释放互斥量解锁进入阻塞状态等待另外进程唤醒,这两个动作之间是原子性的,保证这个过程中不会错过任何唤醒信号。

1
2
int sem_wait(sem_t *sem)
int sem_post(sem_t *sem)

3、信号量,原子性减少、增加。

条件变量版本:

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
90
91
92
93
94
95
#include 
#include 
 
#define BUFFER_SIZE 4
#define OVER (-1)
 
struct producers{
//定义生产者条件变量的结构
int buffer[BUFFER_SIZE];//定义缓冲区
pthread_mutex_t lock;//定义访问缓冲区的互斥锁
int readpos,writepos;//读写位置指针
pthread_cond_t notempty;//缓冲区中有数据时的标记
pthread_cond_t notfull;//缓冲区未满的标记
};
 
//初始化缓冲区
void init(struct producers *b){
pthread_mutex_init(&b->lock,NULL);
pthread_cond_init(&b->notempty,NULL);
pthread_cond_init(&b->notfull,NULL);
b->readpos = 0;
b->writepos = 0;
}
 
//在缓冲区中存放一个整数
void put(struct producers *b,int data){
pthread_mutex_lock(&b->lock);
//当缓冲区为满时等待
while((b->writepos+1)%BUFFER_SIZE==b->readpos){
pthread_cond_wait(&b->notfull,&b->lock);
}
 
b->buffer[b->writepos] = data;
b->writepos++;
if(b->writepos>=BUFFER_SIZE)
b->writepos = 0;
//发送当前缓冲区中有数据的信号
pthread_cond_signal(&b->notempty);
pthread_mutex_unlock(&b->lock);
}
 
//从缓冲区中读数据并将数据从缓冲区中移走
int get(struct producers *b){
int data;
pthread_mutex_lock(&b->lock);
 
while(b->writepos==b->readpos){
pthread_cond_wait(&b->notempty,&b->lock);
}
 
//从缓冲区读数据,并将指针前移
data = b->buffer[b->readpos];
b->readpos++;
if(b->readpos>=BUFFER_SIZE)
b->readpos = 0;
//发送当前缓冲区未满的信号
pthread_cond_signal(&b->notfull);
pthread_mutex_unlock(&b->lock);
return data;
}
 
struct producers buffer;
void *producer(void *data){
int n;
for(n = 0;n<10;n++){ printf("Producer:%d-->\n",n);
put(&buffer,n);
}
put(&buffer,OVER);
return NULL;
 
}
 
void *consumer(void *data){
int d;
while(1){
d = get(&buffer);
if(d==OVER){
break;
}
printf("Consumer:-->%d\n",d);
 
}
return NULL;
}
 
int main(){
pthread_t tha,thb;
void *retval;
init(&buffer);
pthread_create(&thb,NULL,consumer,0);
pthread_create(&tha,NULL,producer,0);
pthread_join(tha,&retval);
pthread_join(thb,&retval);
return 0;
}

信号量例子:

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
#include 
#include 
#include  
 
#define BUFFER_SIZE 4
#define OVER (-1)
 
struct producers{
    int buffer[BUFFER_SIZE];
    int readpos,writepos;//读写位置
    sem_t sem_read;//可读信号量
    sem_t sem_write;//可写信号量
};
 
void init(struct producers *b){
    sem_init(&b->sem_write,0,BUFFER_SIZE-1);
    sem_init(&b->sem_read,0,0);
    b->readpos = 0;
    b->writepos = 0;
}
 
void put(struct producers *b, int data){
    sem_wait(&b->sem_write);
    b->buffer[b->writepos] = data;
    b->writepos++;
    if(b->writepos>=BUFFER_SIZE) b->writepos = 0;
    sem_post(&b->sem_read);
}
 
int get(struct producers *b){
    int data;
    sem_wait(&b->sem_read);
    data = b->buffer[b->readpos];
    b->readpos++;
    if(b->readpos >= BUFFER_SIZE) b->readpos = 0;
    sem_post(&b->sem_write);
    return data;
}
 
struct producers buffer;
void *producer(void *data){
    int n;
    for(n = 0;n <10; n++){         printf("Producer : %d-->\n",n);
        put(&buffer, n);
    }
    put(&buffer,OVER);
    return NULL;
}
 
void *consumer(void *data){
    int d;
    while(1){
        d = get(&buffer);
        if(d == OVER) break;
        printf("Consumer: --> %d\n",d);
    }
    return NULL;
}
 
int main(){
    pthread_t tha,thb;
    void *retval;
    init(&buffer);
    pthread_create(&tha, NULL, producer, 0);
    pthread_create(&thb, NULL, consumer, 0);
    pthread_join(tha, &retval);
    pthread_join(thb, &retval);
    return 0;
}

文章摘抄:Linux C编程–线程操作2–线程同步详解

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注

您可以使用这些HTML标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>