1.题目要求
使用信号量解决生产者、计算者、消费者问题
- 功能和前面的实验相同,使用信号量解决
2.解决思路
生产者、计算者、消费者三个线程的逻辑与上一题使用条件变量解决生产者、计算者、消费者问题相同,不同之处在于本题使用条件变量实现信号量sema_t
,value
记录了信号量的值。sema_wait
函数如果信号量的值小于等于0,则等待条件变量将信号量的值减一。sema_signal
函数将信号量的值加一,唤醒等待条件变量的线程。定义mutex_sema
用于互斥访问共享缓冲区变量in
/out
,empty_buffer_sema
/full_buffer_sema
用于线程同步(对buffer1
和buffer2
分别定义上述若干个变量)。在main
函数中进行sema_init
初始化操作,在生产者、计算者、消费者线程函数中可以直接调用sema_wait
和sema_signal
进行申请信号量和释放信号量。
3.代码
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#define CAPACITY 4
#define ITEM_COUNT 8
int buffer1[CAPACITY], buffer2[CAPACITY];
int in1, in2;
int out1, out2;
typedef struct {
int value;
pthread_mutex_t mutex;
pthread_cond_t cond;
} sema_t;
sema_t mutex1_sema, mutex2_sema;
sema_t empty_buffer1_sema, empty_buffer2_sema;
sema_t full_buffer1_sema, full_buffer2_sema;
// buffer1
int buffer1_is_empty() {
return in1 == out1;
}
int buffer1_is_full() {
return (in1 + 1) % CAPACITY == out1;
}
int get_item1() {
int item = buffer1[out1];
out1 = (out1 + 1) % CAPACITY;
return item;
}
void put_item1(int item) {
buffer1[in1] = item;
in1 = (in1 + 1) % CAPACITY;
}
// buffer2
int buffer2_is_empty() {
return in2 == out2;
}
int buffer2_is_full() {
return (in2 + 1) % CAPACITY == out2;
}
int get_item2() {
int item = buffer2[out2];
out2 = (out2 + 1) % CAPACITY;
return item;
}
void put_item2(int item) {
buffer2[in2] = item;
in2 = (in2 + 1) % CAPACITY;
}
// sema
void sema_init(sema_t *sema, int value) {
sema->value = value;
pthread_mutex_init(&sema->mutex, NULL);
pthread_cond_init(&sema->cond, NULL);
}
void sema_wait(sema_t *sema) {
pthread_mutex_lock(&sema->mutex);
while(sema->value <= 0)
pthread_cond_wait(&sema->cond, &sema->mutex);
--sema->value;
pthread_mutex_unlock(&sema->mutex);
}
void sema_signal(sema_t *sema) {
pthread_mutex_lock(&sema->mutex);
++sema->value;
pthread_cond_signal(&sema->cond);
pthread_mutex_unlock(&sema->mutex);
}
// 生产者
void *produce(void *arg) {
int item, i;
for(i = 0; i < ITEM_COUNT; i++) {
sema_wait(&empty_buffer1_sema);
sema_wait(&mutex1_sema);
item = 'a' + i;
printf("produce item: %c\n", item);
put_item1(item);
sema_signal(&mutex1_sema);
sema_signal(&full_buffer1_sema);
}
return NULL;
}
// 计算者
void *compute(void *arg) {
int item, i;
for(i = 0; i < ITEM_COUNT; i++) {
sema_wait(&full_buffer1_sema);
sema_wait(&mutex1_sema);
item = get_item1();
printf("\t\tcompute item before: %c\n", item);
item = item - 32;
printf("\t\tcompute item after : %c\n", item);
sema_signal(&mutex1_sema);
sema_signal(&empty_buffer1_sema);
sema_wait(&empty_buffer2_sema);
sema_wait(&mutex2_sema);
put_item2(item);
sema_signal(&mutex2_sema);
sema_signal(&full_buffer2_sema);
}
return NULL;
}
// 消费者
void *consume(void *arg) {
int item, i;
for(i = 0; i < ITEM_COUNT; i++) {
sema_wait(&full_buffer2_sema);
sema_wait(&mutex2_sema);
item = get_item2();
printf("\t\t\t\t\tconsume item: %c\n", item);
sema_signal(&mutex2_sema);
sema_signal(&empty_buffer2_sema);
}
return NULL;
}
int main() {
pthread_t computer_tid, consumer_tid;
sema_init(&mutex1_sema, 1);
sema_init(&mutex2_sema, 1);
sema_init(&empty_buffer1_sema, CAPACITY - 1);
sema_init(&empty_buffer2_sema, CAPACITY - 1);
sema_init(&full_buffer1_sema, 0);
sema_init(&full_buffer2_sema, 0);
pthread_create(&computer_tid, NULL, compute, NULL);
pthread_create(&consumer_tid, NULL, consume, NULL);
produce(NULL);
pthread_join(computer_tid, NULL);
pthread_join(consumer_tid, NULL);
return 0;
}
4.运行结果
$ gcc pc2.c -lpthread
$ ./a.out
produce item: a
produce item: b
produce item: c
compute item before: a
compute item after : A
compute item before: b
compute item after : B
compute item before: c
compute item after : C
consume item: A
consume item: B
consume item: C
produce item: d
produce item: e
produce item: f
compute item before: d
compute item after : D
produce item: g
compute item before: e
compute item after : E
compute item before: f
compute item after : F
compute item before: g
compute item after : G
produce item: h
consume item: D
consume item: E
consume item: F
compute item before: h
compute item after : H
consume item: G
consume item: H