第一关 生产者与消费者问题
一.变量声明
#define PRODUCER_NUM 5 //定义生产者数量
#define CONSUMER_NUM 5 //定义消费者数量
sem_t full, empty, mutex1, mutex2 //定义信号量
//full和empty实现生产者和消费者同步
//mutex1实现生产者之间互斥,mutex2实现消费者之间互斥
二.produce函数
void *produce(void *id){ //增加参数:生产者编号,注意为void *类型
int i;
const int pid = *(int*)id; //类型转换
for (i = 0; i < PRODUCT_NUM; i++){
sleep_random(2);
sem_wait(&empty);
sem_wait(&mutex1); //生产者之间互斥
buffer[writepos++] = 1000 * pid + i + 1; //修改编号
if (writepos >= N)
writepos = 0;
printf("produce: %d\n", 1000 * pid + i + 1); //修改输出
sem_post(&mutex1); //生产者之间互斥
sem_post(&full);
}
}
三.consume函数
void *consume(void *id){ //增加参数:消费者编号,注意为void *类型
int i;
const int cid = *(int*)id; //类型转换
for (i = 0; i < PRODUCT_NUM; i++){
sleep_random(2);
sem_wait(&full);
sem_wait(&mutex2); //消费者之间互斥
printf("%d consume: %d\n", cid, buffer[readpos]); //修改输出
buffer[readpos++] = - 1;
if (readpos >= N)
readpos = 0;
sem_post(&mutex2); //消费者之间互斥
sem_post(&empty);
}
}
四.main函数
int main(){
int i, producer_id[PRODUCER_NUM], consumer_id[CONSUMER_NUM]; //声明存储编号的数组
pthread_t producer_t[PRODUCER_NUM]; //声明存储线程的数组
pthread_t consumer_t[CONSUMER_NUM]; //每一个生产者和消费者都有一个线程
for (i = 0; i < N; i++)
buffer[i] = - 1;
srand((int)time(0));
sem_init(&full, 0, 0); //信号量初始化
sem_init(&empty, 0, N);
sem_init(&mutex1, 0, 1); //mutex1和mutex2用于实现互斥,故初值为1
sem_init(&mutex2, 0, 1);
for (i = 0; i < PRODUCER_NUM; i++){ //创建线程
producer_id[i] = i + 1;
pthread_create(&producer_t[i], NULL, produce, &producer_id[i]);
}
for (i = 0; i < CONSUMER_NUM; i++){
consumer_id[i] = i + 1;
pthread_create(&consumer_t[i], NULL, consume, &consumer_id[i]);
}
for (i = 0; i < PRODUCER_NUM; i++) //等待线程结束
pthread_join(producer_t[i], NULL);
for (i = 0; i < CONSUMER_NUM; i++)
pthread_join(consumer_t[i], NULL);
return 0;
}
第二关 三个并发进程
一.变量声明
int buffer_P_Q[M], buffer_Q_R[N], readpos_P_Q = 0, writepos_P_Q = 0, readpos_Q_R = 0, writepos_Q_R = 0;
//缓冲池和各自的读写位置声明加初始化
sem_t full_P_Q, empty_P_Q, full_Q_R, empty_Q_R;
//信号量声明,full_P_Q和empty_P_Q实现PQ同步,full_Q_R和empty_Q_R实现QR同步
二.P函数
sem_wait(&empty_P_Q); //实现PQ同步
buffer_P_Q[writepos_P_Q++] = i + 1; //读取信息放入缓冲池1
if (writepos_P_Q >= M) //放满了,重置
writepos_P_Q = 0;
printf("sends: %d\n", i + 1); //打印读取的信息
sem_post(&full_P_Q); //实现PQ同步
三.Q函数
sem_wait(&full_P_Q); //实现PQ同步
data = buffer_P_Q[readpos_P_Q]; //从缓冲池1中读取信息
buffer_P_Q[readpos_P_Q] = -1; //表示信息已被读走
readpos_P_Q++;
if (readpos_P_Q >= M) //重置
readpos_P_Q = 0;
sem_post(&empty_P_Q); //实现PQ同步
sem_wait(&empty_Q_R); //实现QR同步
buffer_Q_R[writepos_Q_R++] = data; //将读取的信息放进缓冲池2
if (writepos_Q_R >= N) //重置
writepos_Q_R = 0;
sem_post(&full_Q_R); //实现QR同步
三.R函数
sem_wait(&full_Q_R); //实现QR同步
printf("receives: %d\n", buffer_Q_R[readpos_Q_R]); //输出信息
buffer_Q_R[readpos_Q_R++] = -1; //表示信息已被读走
if (readpos_Q_R >= N) //重置
readpos_Q_R = 0;
sem_post(&empty_P_Q); //实现QR同步
四.main函数
sem_init(&full_P_Q, 0, 0); //信号量初始化
sem_init(&empty_P_Q, 0, M);
sem_init(&full_Q_R, 0, 0);
sem_init(&empty_Q_R, 0, N);
第三关 理发师问题
一.变量声明
sem_t start, finish, empty_rest, empty_cut;
//信号量声明,start和finish实现“顾客进入理发室”和“理发师理发(barber)”过程的同步
//empty_rest实现进入休息室的顾客之间的互斥,empty_cut实现进入理发室的顾客之间的互斥
二.barber函数
sem_wait(&start); //实现“顾客进入理发室”和“理发师理发(barber)”过程的同步
sem_post(&finish);
三.customer函数
sem_wait(&empty_rest)可理解为:休息室没有空位时必须等待
sem_wait(&empty_cut)可理解为:理发室没有空位时必须等待
sem_post(&empty_rest)可理解为:顾客已进入理发室,所以“顾客进入休息室”过程已结束,可以把“锁”解开了
sem_post(&start)是保证“顾客进入休息室”在“理发师为该顾客理发”之前发生
sem_wait(&finish)可理解为:顾客进入了理发室,但需要等待理发师给上一个顾客理完
sem_post(&empty_cut)可理解为:顾客开始理发,以“顾客进入理发室”过程已结束,可以把“锁”解开了
四.main函数
sem_init(&start ,0 ,0); //empty_rest和empty_cut是实现同步的信号量,故初值应为1
sem_init(&finish ,0 ,0);
sem_init(&empty_rest ,0 ,2); //休息室有2个位置
sem_init(&empty_cut ,0 ,1); //理发室有1个位置
注意:
1.只能在原文件基础上修改,不能创建新的文件。
2.修改完毕后,在/data/workspace/myshixun/exp3目录下使用gcc 4-x.c -pthread编译,然后可以用./a.out运行测试。评测前要把修改后的4-x.c文件拷贝到/myshixun目录下,否则会报错找不到文件。