首先我们来介绍一下“C语言中的睡眠理发师问题”是什么。
“C语言中的睡眠理发师问题”是一个经典的操作系统并发问题,用于模拟多线程的同步、互斥等问题。问题可以描述为:在一个理发店中,有一个理发师和若干个等待理发的顾客。理发师和每位顾客都是一个独立的线程,理发师依次为每位等待的顾客理发,每位顾客进入理发椅前都需要等待理发师叫号。如果顾客到达时店里有顾客正在理发,则顾客将等待。当然,如果没有顾客等待,则理发师会睡觉。我们需要在C语言中实现这个问题的解决方案。
对于这个问题解决方案,我们可以使用Pthread库来实现多线程的同步与互斥。具体来说,我们需要使用Pthread库中的互斥锁、条件变量等机制来保证理发师和顾客之间的同步与互斥。在Pthread库中,我们可以使用pthread_mutex_init、pthread_mutex_lock、pthread_mutex_unlock等函数来实现互斥锁的初始化、加锁、解锁。同时,也可以使用pthread_cond_init、pthread_cond_signal、pthread_cond_wait等函数来实现条件变量的初始化、发送信号、等待信号等操作。具体实现细节可以参考下面的示例代码。
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
int waiting = 0; //等待理发的顾客数
int done = 0; //理发完成的顾客数
int barber_sleeping = 0; //理发师是否在睡觉
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; //定义互斥锁
pthread_cond_t customers = PTHREAD_COND_INITIALIZER; //定义条件变量
pthread_cond_t barber = PTHREAD_COND_INITIALIZER; //定义条件变量
void* barber_thread(void* arg) { //理发师线程函数
while(1) {
pthread_mutex_lock(&mutex); //加锁
if(waiting == 0) { //无顾客,则睡觉
printf("Barber is sleeping.\n");
barber_sleeping = 1;
pthread_cond_wait(&customers, &mutex); //等待顾客
barber_sleeping = 0;
}
waiting--; //从等待队列中去除一位顾客
printf("Barber is cutting hair for customer %d\n", done+1);
done++; //理发
pthread_mutex_unlock(&mutex); //解锁
sleep(2); //模拟理发过程
}
}
void* customer_thread(void* arg) { //顾客线程函数
int id = *(int*)arg;
pthread_mutex_lock(&mutex); //加锁
printf("Customer %d arrives.\n", id+1);
if(waiting == 0 && barber_sleeping) { //理发师正在睡觉,则叫醒他
printf("Customer %d wakes up the barber.\n", id+1);
pthread_cond_signal(&customers);
barber_sleeping = 0;
}
else if(waiting > 0) { //已有顾客等待,则加入等待队列
printf("Customer %d joins the queue.\n", id+1);
}
waiting++; //加入等待队列
pthread_mutex_unlock(&mutex); //解锁
pthread_cond_wait(&barber, &mutex); //等待理发完成
printf("Customer %d leaves.\n", id+1);
}
int main() {
const int n_customers = 10;
pthread_t barber_tid, customer_tid[n_customers];
pthread_create(&barber_tid, NULL, barber_thread, NULL); //创建理发师线程
for(int i = 0; i < n_customers; i++) {
sleep(rand() % 3); //随机睡眠一段时间
pthread_create(&customer_tid[i], NULL, customer_thread, (void*)&i); //创建顾客线程
}
for(int i = 0; i < n_customers; i++) {
pthread_join(customer_tid[i], NULL); //等待顾客线程结束
}
return 0;
}
上述代码中,我们先定义了等待理发的顾客数、理发完成的顾客数、理发师是否在睡觉三个全局变量,以及互斥锁和条件变量三个全局变量。之后,我们分别实现了理发师线程函数和顾客线程函数。理发师线程函数通过加锁、解锁和等待信号等机制来模拟理发的过程,当无顾客等待时,理发师会睡觉,等到有顾客到来时再起床为其理发;而当有顾客等待时,理发师会依次为各位顾客理发。顾客线程函数则通过加锁、解锁和等待信号等机制来模拟到店、等待、进入理发椅、离开等过程。最后,在主函数中,我们创建了一个理发师线程和多个顾客线程,并通过调用pthread_create函数和pthread_join函数来启动和等待线程的执行。
接下来我们来看两个具体的示例说明。
示例1:模拟一天的理发生意
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
int waiting = 0; //等待理发的顾客数
int done = 0; //理发完成的顾客数
int barber_sleeping = 0; //理发师是否在睡觉
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; //定义互斥锁
pthread_cond_t customers = PTHREAD_COND_INITIALIZER; //定义条件变量
pthread_cond_t barber = PTHREAD_COND_INITIALIZER; //定义条件变量
void* barber_thread(void* arg) { //理发师线程函数
while(done < 10) { //理发师一天最多为10位顾客理发
pthread_mutex_lock(&mutex); //加锁
if(waiting == 0) { //无顾客,则睡觉
printf("Barber is sleeping.\n");
barber_sleeping = 1;
pthread_cond_wait(&customers, &mutex); //等待顾客
barber_sleeping = 0;
}
waiting--; //从等待队列中去除一位顾客
printf("Barber is cutting hair for customer %d\n", done+1);
done++; //理发
pthread_mutex_unlock(&mutex); //解锁
sleep(2); //模拟理发过程
}
}
void* customer_thread(void* arg) { //顾客线程函数
int id = *(int*)arg;
pthread_mutex_lock(&mutex); //加锁
printf("Customer %d arrives.\n", id+1);
if(waiting == 0 && barber_sleeping) { //理发师正在睡觉,则叫醒他
printf("Customer %d wakes up the barber.\n", id+1);
pthread_cond_signal(&customers);
barber_sleeping = 0;
}
else if(waiting > 0) { //已有顾客等待,则加入等待队列
printf("Customer %d joins the queue.\n", id+1);
}
waiting++; //加入等待队列
pthread_mutex_unlock(&mutex); //解锁
pthread_cond_wait(&barber, &mutex); //等待理发完成
printf("Customer %d leaves.\n", id+1);
}
int main() {
pthread_t barber_tid, customer_tid[15];
pthread_create(&barber_tid, NULL, barber_thread, NULL); //创建理发师线程
for(int i = 0; i < 15; i++) {
sleep(rand() % 5); //模拟到店时间
pthread_create(&customer_tid[i], NULL, customer_thread, (void*)&i); //创建顾客线程
}
for(int i = 0; i < 15; i++) {
pthread_join(customer_tid[i], NULL); //等待顾客线程结束
}
pthread_cancel(barber_tid); //关闭理发师线程
printf("The barber shop closes.\n");
return 0;
}
上述示例中,我们模拟了一天的理发生意,每个顾客在到店后会等待一段时间后发现理发师正在睡觉,则会叫醒他并进行理发;或者等待前面的顾客理发完成后再进行理发。而理发师则一直进行理发直到完成10位顾客的理发。最后,我们关闭理发师线程并输出“The barber shop closes.”。
运行结果:
Barber is sleeping.
Customer 1 arrives.
Customer 1 wakes up the barber.
Barber is cutting hair for customer 1
Customer 2 arrives.
Customer 2 joins the queue.
Customer 3 arrives.
Customer 3 joins the queue.
Barber is cutting hair for customer 2
Customer 4 arrives.
Customer 4 joins the queue.
Barber is cutting hair for customer 3
Customer 5 arrives.
Customer 5 joins the queue.
Barber is cutting hair for customer 4
Customer 6 arrives.
Customer 6 joins the queue.
Customer 7 arrives.
Customer 7 joins the queue.
Barber is cutting hair for customer 5
Customer 8 arrives.
Customer 8 joins the queue.
Barber is cutting hair for customer 6
Barber is cutting hair for customer 7
Customer 9 arrives.
Customer 9 joins the queue.
Barber is cutting hair for customer 8
Customer 10 arrives.
Customer 10 joins the queue.
Barber is cutting hair for customer 9
Barber is cutting hair for customer 10
The barber shop closes.
示例2:添加日志记录功能
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <time.h>
int waiting = 0; //等待理发的顾客数
int done = 0; //理发完成的顾客数
int barber_sleeping = 0; //理发师是否在睡觉
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; //定义互斥锁
pthread_cond_t customers = PTHREAD_COND_INITIALIZER; //定义条件变量
pthread_cond_t barber = PTHREAD_COND_INITIALIZER; //定义条件变量
void* barber_thread(void* arg) { //理发师线程函数
while(done < 10) { //理发师一天最多为10位顾客理发
pthread_mutex_lock(&mutex); //加锁
if(waiting == 0) { //无顾客,则睡觉
printf("[%s] Barber is sleeping.\n", \
asctime(localtime(&(time_t){time(NULL)})));
barber_sleeping = 1;
pthread_cond_wait(&customers, &mutex); //等待顾客
barber_sleeping = 0;
}
waiting--; //从等待队列中去除一位顾客
printf("[%s] Barber is cutting hair for customer %d\n", \
asctime(localtime(&(time_t){time(NULL)})), done+1);
done++; //理发
pthread_cond_signal(&barber); //发送理发完成信号
pthread_mutex_unlock(&mutex); //解锁
sleep(2); //模拟理发过程
}
}
void* customer_thread(void* arg) { //顾客线程函数
int id = *(int*)arg;
pthread_mutex_lock(&mutex); //加锁
printf("[%s] Customer %d arrives.\n", \
asctime(localtime(&(time_t){time(NULL)})), id+1);
if(waiting == 0 && barber_sleeping) { //理发师正在睡觉,则叫醒他
printf("[%s] Customer %d wakes up the barber.\n", \
asctime(localtime(&(time_t){time(NULL)})), id+1);
pthread_cond_signal(&customers);
barber_sleeping = 0;
}
else if(waiting > 0) { //已有顾客等待,则加入等待队列
printf("[%s] Customer %d joins the queue.\n", \
asctime(localtime(&(time_t){time(NULL)})), id+1);
}
waiting++; //加入等待队列
pthread_mutex_unlock(&mutex); //解锁
pthread_cond_wait(&barber, &mutex); //等待理发完成
printf("[%s] Customer %d leaves.\n", \
asctime(localtime(&(time_t){time(NULL)})), id+1);
}
int main() {
pthread_t barber_tid, customer_tid[15];
pthread_create(&barber_tid, NULL, barber_thread, NULL); //创建理发师线程
for(int i = 0; i < 15; i++) {
sleep(rand() % 5); //模拟到店时间
pthread_create(&customer_tid[i], NULL, customer_thread, (void*)&i); //创建顾客线程
}
for(int i = 0; i < 15; i++) {
pthread_join(customer_tid[i], NULL); //等待顾客线程结束
}
pthread_cancel(barber_tid); //关闭理发师线程
printf("[%s] The barber shop closes.\n", \
asctime(localtime(&(time_t){time(NULL)})));
return 0;
}
在上述示例中,我们添加了日志记录功能,利用asctime和localtime函数可以在日志输出中加入当前时间。同时,为了保证理发完成后及时通知顾客,我们在理发师线程函数中发送了理发完成信号pthread_cond_signal。最后,我们输出“[time] The barber shop closes.”表示营业结束。
运行结果:
```
[Wed Sep 15 22:34:44 2021] Customer 1 arrives.
[Wed Sep 15 22:34:44 2021] Customer 1 wakes up the barber.
[Wed Sep 15 22:34:44 2021] Barber is cutting hair for customer 1
[Wed Sep 15 22:34:46 2021] Customer 2 arrives.
[Wed Sep 15 22:34:46 2021] Customer 2 joins the queue.
[Wed Sep 15 22:34:48 2021] Customer 3 arrives.
[Wed Sep 15 22:34:48 2021] Customer 3 joins the queue.
[Wed Sep 15 22:34:50 2021] Barber is cutting hair for customer 2
[Wed Sep 15 22:34:51 2021] Customer 4 arrives.
[Wed Sep 15 22:34:51 2021] Customer 4 joins the queue.
[Wed Sep 15 22:34:53 2021] Barber is cutting hair for customer 3
[Wed Sep 15 22:34:54 2021] Customer 5 arrives.
[Wed Sep 15 22:34:54 2021] Customer 5 joins the queue.
[Wed Sep 15 22:34:56 2021] Barber is cutting hair for customer 4
[Wed Sep 15 22:34:57 2021] Customer 6 arrives.
[Wed Sep 15 22:34:57 2021] Customer 6 joins the queue.
[Wed Sep 15 22:34:58 2021] Customer 7 arrives.
[Wed Sep 15 22:34:58 2021] Customer 7 joins the queue.
[Wed Sep 15 22:34:59 2021] Barber is cutting hair for customer 5
[Wed Sep 15 22:35:01 2021] Customer 8 arrives.
[Wed
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C语言中的睡眠理发师问题解决方案 - Python技术站