C语言中的睡眠理发师问题解决方案

首先我们来介绍一下“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技术站

(0)
上一篇 2023年5月9日
下一篇 2023年5月9日

相关文章

  • C语言实现扫雷游戏小项目

    C语言实现扫雷游戏小项目攻略 1. 项目需求 本项目是一个简单的命令行扫雷游戏,主要需求如下: 使用C语言编写; 实现基础的扫雷游戏逻辑、界面和操作; 实现自定义雷区难度选择功能; 实现输赢判断和计分功能。 2. 项目实现思路 2.1 界面设计 扫雷游戏的主界面应该包含以下元素: 雷区:即扫雷主要游戏区域,显示方格和地雷的分布情况; 游戏操作区:便于玩家控制…

    C 2023年5月23日
    00
  • 如何解决Win10更新错误0x8024401c怎么办?Win10更新失败错误0x8024401c的解决方法

    针对Win10更新错误0x8024401c,以下是解决方法的完整攻略: 1. 检查网络连接 首先要检查网络连接是否正常,这是Win10更新失败的主要原因之一。可以尝试以下方法进行检查: 第一步:打开浏览器,打开任意网页,查看是否能正常访问; 第二步:确保网络连接正常,并尝试重新连接; 第三步:如果网络连接正常,尝试断开并重新连接网络,查看问题是否得到解决。 …

    C 2023年5月23日
    00
  • C 程序结构

    C 程序结构 C 语言程序一般由三部分组成,它们分别是: 预处理部分 主函数 子函数 预处理部分 预处理部分是在程序编译前执行的,主要作用是进行宏定义、条件编译、头文件包含等处理。 预处理命令都以#开头,常用的预处理命令有 #include、#define、#ifdef、#ifndef、#endif 等,其中 #include 用于包含头文件,#define…

    C 2023年5月10日
    00
  • C++两个cpp文件间如何进行各自函数的调用方式

    当我们在一个项目中有多个 C++ 源文件时,我们需要知道如何在不同的文件中调用其它文件的函数。 下面是两个cpp文件间如何进行各自函数的调用方式的攻略: 声明和定义 要在一个文件中使用另一个文件中定义的函数,我们必须将该函数的定义标记为 “extern”,并在需要使用它的文件中进行声明。 例如,如果我们有两个文件,一个叫做 main.cpp 和另一个叫做 h…

    C 2023年5月23日
    00
  • C语言实现返回字符串函数的四种方法

    下面为你详细展开C语言实现返回字符串函数的四种方法的完整攻略。 1. 使用字符串指针 步骤: 定义一个函数,函数返回值为 char * 类型,表示返回一个字符串指针; 在函数内部申请一个指针指向堆内存区域,并在该区域中保存返回的字符串; 返回指针。 示例: #include <stdio.h> #include <stdlib.h> …

    C 2023年5月23日
    00
  • C语言详解如何实现顺序栈

    当我们需要实现一个顺序栈时,需要先定义栈结构体,然后实现栈的基本操作,包括入栈、出栈等。以下为具体步骤: 1. 定义栈结构体 定义一个结构体,包含栈的基本属性: typedef struct SeqStack { int *data; // 栈的元素存储空间 int size; // 栈的大小 int top; // 栈顶指针 } SeqStack; 其中,…

    C 2023年5月23日
    00
  • Win7升级Win10系统失败提示错误代码0x8007002c-0x4000D的解决方法

    Win7升级Win10系统失败提示错误代码0x8007002c-0x4000D的解决方法 在进行Win7升级Win10系统时,有时会出现错误代码0x8007002c-0x4000D的提示,这种情况一般是由于系统出现错误、网络连接问题以及硬件设备驱动问题等引起的。下面就为大家介绍几种常用的解决方法。 方法一:清理系统垃圾文件和重启系统 在升级Win10系统之前…

    C 2023年5月24日
    00
  • C语言示例讲解do while循环语句的用法

    C语言示例讲解do while循环语句的用法 什么是do while循环语句 do while循环语句是一种循环结构,它先执行一次循环体,再根据判断条件是否成立来决定是否继续执行循环体。与while循环语句不同的是,do while循环语句至少会执行一次循环体。 do while循环语句的基本格式如下: do { 循环体语句; } while (判断条件);…

    C 2023年5月22日
    00
合作推广
合作推广
分享本页
返回顶部