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

yizhihongxing

首先我们来介绍一下“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语言零基础彻底掌握预处理下篇”的完整攻略。 一、预处理概述 在了解C语言预处理下篇之前,我们先来了解一下预处理的概念和作用。 预处理器是C语言的编译器的组成部分,可以看成是在编译正式开始之前对源程序的预先处理。它会将源程序中以“#”开头的预处理指令(例如#include、#define、#ifdef等)进行处理,生成新的源程序,并将…

    C 2023年5月23日
    00
  • C语言 指针

    下面是关于C语言指针的完整使用攻略: 简介 指针是一种特殊的变量类型,它存储内存地址的值。通过指针,可以改变变量的值或者访问已分配的堆内存中的值。指针在C语言中具有重要的地位,理解指针也是C语言编程的基础之一。 指针的定义 指针定义的一般形式为:数据类型 *指针变量名。其中,数据类型是指针所指向的变量类型,指针变量名是指针变量在程序中的标识符。 示例: in…

    C 2023年5月9日
    00
  • C++中new和delete的介绍

    C++中new和delete是用于动态内存分配和释放的操作符,本文将为大家详细讲解其用法和注意事项。 new 新建对象 C++中,我们可以使用new操作符在堆上分配内存,从而创建一个新对象。使用new的语法如下: type *pointer = new type; 其中type表示对象的类型,pointer是指向新分配对象的指针。 例如,在以下示例中,我们使…

    C 2023年5月23日
    00
  • C语言实现简单的定时器

    下面是详细讲解“C语言实现简单的定时器”的完整攻略。 一、定时器基本概念 在计算机中,定时器是一种可以精确测量时间的硬件或软件设备。它可以用于各种计算机程序中,比如处理定时任务、测量延迟等等。 一般来说,定时器都会有一个计数器,当计数器达到一定值后,就会触发一个中断以执行相关处理。在实际编程中,我们需要用到定时器,往往需要先初始化定时器并设置计数器的初值和中…

    C 2023年5月22日
    00
  • C++浅析析构函数的特征

    C++浅析析构函数的特征 在C++中,析构函数是一个类的特殊成员函数。它是在对象被销毁时调用的,用于清理对象的资源。析构函数的特征由以下几个方面组成。 析构函数的命名 析构函数的命名与类名相同,但它在前面加上一个波浪号(~)。例如,如果类名为MyClass,那么析构函数的命名应为~MyClass()。 析构函数的返回类型 析构函数没有返回值,它的返回类型必须…

    C 2023年5月22日
    00
  • 简单谈谈C++ 中指针与引用

    下面是关于C++中指针与引用的详细讲解: 指针与引用简介 在C++中,指针和引用都属于变量地址的概念,它们可以被用来实现对变量的间接访问。指针是一个变量,存储着另一个变量的地址,而引用则是一个别名,是被引用变量的另一个名称。 指针和引用都是C++中重要的概念,尤其是在使用函数传参和动态内存分配时,它们常被使用。 指针的使用 在C++中,可以使用指针来实现对另…

    C 2023年5月23日
    00
  • C语言利用模板实现简单的栈类

    C语言利用模板实现简单的栈类 概述 本文介绍如何利用C语言中的模板来实现一个简单的栈类,使用者可以通过该类方便地进行基本的栈操作,比如入栈、出栈、查看栈顶元素等。 设计思路 栈是一种后进先出的数据结构,本文中我们采用单向链表的形式来实现栈,每个节点存储一个数据元素,同时每个节点还有个指向下一个节点的指针。栈的主要操作为入栈、出栈、查看栈顶元素,我们在代码中实…

    C 2023年5月23日
    00
  • C语言实现猜数字小游戏

    以下是详细讲解“C语言实现猜数字小游戏”的完整攻略。 第一步:获取用户输入的数字 为实现猜数字小游戏的基本功能,首先需要获取用户输入的数字。可以使用C语言的标准库函数scanf()来实现。示例代码如下: int guess_num; // 定义变量来存储用户输入的数字 printf("请猜一个数字:"); scanf("%d&q…

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