当前位置: 首页 > news >正文

Linux多线程编程-哲学家就餐问题详解与实现(C语言)

在哲学家就餐问题中,假设有五位哲学家围坐在圆桌前,每位哲学家需要进行思考和进餐两种活动。他们的思考不需要任何资源,但进餐需要使用两根筷子(左右两侧各一根)。筷子是共享资源,哲学家们在进行进餐时需要竞争筷子,而且不能出现死锁情况,即每位哲学家都能在有可能的情况下进餐。

问题示例:

假设有五位哲学家,编号为 0 到 4,围坐在圆桌周围,每位哲学家面前有一根筷子。他们的行为可以描述如下:

  1. 思考:哲学家在没有筷子的时候,思考一段时间。

  2. 进餐:哲学家只有同时拿到左右两边的筷子才能进餐,进餐完成后放下筷子继续思考。

解决方案概述:

  1. 状态记录:每位哲学家有三种状态:思考、饥饿和进餐。
  2. 互斥保护:使用互斥锁保护对状态的访问,确保状态变化的原子性。
  3. 信号量:使用信号量控制每根筷子的使用,确保每位哲学家能同时拿到左右两根筷子。

我们用一个数组 state 来记录每一位哲学家的三个状态,分别是在进餐状态、思考状态、饥饿状态(正在试图拿叉子)。

那么,一个哲学家只有在两个邻居都没有进餐时,才可以进入进餐状态。

第 i 个哲学家的左邻右舍,则由宏 LEFT 和 RIGHT 定义:

  • LEFT : ( i + 5 - 1 ) % 5
  • RIGHT : ( i + 1 ) % 5

比如 i 为 2,则 LEFT 为 1,RIGHT 为 3。

解决步骤:

  1. 定义全局变量和初始化

    • 定义哲学家状态数组 state[],互斥锁 pthread_mutex_t mutex 和信号量数组 sem_t chopsticks[]
    • 初始化互斥锁和每个筷子的信号量。
  2. 哲学家线程函数设计

    • 哲学家线程循环执行思考和进餐过程。
    • 在饥饿状态时,试图获取两侧筷子,获取成功则进餐,否则等待。
    • 进餐后释放筷子,继续思考。
  3. 获取和释放筷子的操作

    • 使用互斥锁保护对状态数组的修改,确保线程安全。
    • 利用信号量控制筷子的获取和释放,避免死锁和资源争夺。

示例代码:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>#define NUM_PHILOSOPHERS 5
#define THINKING 0
#define HUNGRY 1
#define EATING 2int state[NUM_PHILOSOPHERS];  // 哲学家的状态数组
pthread_mutex_t mutex;  // 互斥锁,保护对状态数组的访问
sem_t chopsticks[NUM_PHILOSOPHERS];  // 每根筷子的信号量数组void *philosopher(void *arg) {int id = *((int *)arg);while (1) {// 思考printf("哲学家 %d 正在思考。\n", id);sleep(rand() % 3 + 1);  // 模拟思考时间// 进入饥饿状态printf("哲学家 %d 饿了。\n", id);pthread_mutex_lock(&mutex);state[id] = HUNGRY;printf("哲学家 %d 尝试拿起筷子。\n", id);test(id);  // 尝试获取两侧的筷子pthread_mutex_unlock(&mutex);sem_wait(&chopsticks[id]);  // 获取筷子,如果没有则阻塞// 进餐printf("哲学家 %d 开始进餐。\n", id);sleep(rand() % 3 + 1);  // 模拟进餐时间// 放下筷子sem_post(&chopsticks[id]);  // 放下左侧筷子sem_post(&chopsticks[(id + 1) % NUM_PHILOSOPHERS]);  // 放下右侧筷子printf("哲学家 %d 放下筷子,开始思考。\n", id);}pthread_exit(NULL);
}void test(int id) {if (state[id] == HUNGRY && state[(id + NUM_PHILOSOPHERS - 1) % NUM_PHILOSOPHERS] != EATING&& state[(id + 1) % NUM_PHILOSOPHERS] != EATING) {state[id] = EATING;sem_post(&chopsticks[id]);  // 左侧筷子sem_post(&chopsticks[(id + 1) % NUM_PHILOSOPHERS]);  // 右侧筷子}
}int main() {pthread_t philosophers[NUM_PHILOSOPHERS];int ids[NUM_PHILOSOPHERS];// 初始化互斥锁pthread_mutex_init(&mutex, NULL);// 初始化每根筷子的信号量for (int i = 0; i < NUM_PHILOSOPHERS; ++i) {sem_init(&chopsticks[i], 0, 1);  // 初始值为1,表示筷子可用}// 创建哲学家线程for (int i = 0; i < NUM_PHILOSOPHERS; ++i) {ids[i] = i;pthread_create(&philosophers[i], NULL, philosopher, (void *)&ids[i]);}// 等待线程结束for (int i = 0; i < NUM_PHILOSOPHERS; ++i) {pthread_join(philosophers[i], NULL);}// 清理资源pthread_mutex_destroy(&mutex);for (int i = 0; i < NUM_PHILOSOPHERS; ++i) {sem_destroy(&chopsticks[i]);}return 0;
}

解释和步骤:

1. 全局变量和初始化
  • state[] 数组:每个元素表示一个哲学家的状态,初始为思考状态。
  • pthread_mutex_t mutex:互斥锁,保护对 state[] 数组的访问。
  • sem_t chopsticks[NUM_PHILOSOPHERS] 数组:每根筷子对应一个信号量,初始为可用状态。
2. 哲学家线程函数 philosopher
  • 思考阶段:每个哲学家在思考一段时间后进入饥饿状态。
  • 饥饿阶段:哲学家试图获取左右两根筷子,如果成功则进入进餐状态,否则等待。
  • 进餐阶段:成功获取筷子后进行进餐,一段时间后释放筷子,回到思考阶段。
3. test 函数
  • 检查能否进入进餐状态:检查当前哲学家及其左右邻居的状态,如果都是饥饿状态且两侧筷子可用,则将当前哲学家状态设置为进餐,并释放左右两根筷子。
4. 主函数 main
  • 初始化:初始化互斥锁和每根筷子的信号量。
  • 创建线程:创建并启动每个哲学家的线程。
  • 等待线程结束:主线程等待所有哲学家线程执行完毕。
  • 清理资源:销毁互斥锁和每根筷子的信号量。

相关文章:

Linux多线程编程-哲学家就餐问题详解与实现(C语言)

在哲学家就餐问题中&#xff0c;假设有五位哲学家围坐在圆桌前&#xff0c;每位哲学家需要进行思考和进餐两种活动。他们的思考不需要任何资源&#xff0c;但进餐需要使用两根筷子&#xff08;左右两侧各一根&#xff09;。筷子是共享资源&#xff0c;哲学家们在进行进餐时需要…...

从C向C++18——演讲比赛流程管理系统

一.项目需求 1.比赛规则 学校举行一场演讲比赛&#xff0c;共有12个人参加。比赛共两轮&#xff0c;第一轮为淘汰赛&#xff0c;第二轮为决赛。每名选手都有对应的编号&#xff0c;如 10001~ 10012比赛方式&#xff1a;分组比赛&#xff0c;每组6个人&#xff1b;第一轮分为两…...

QThread和std::thread

在 Qt 中&#xff0c; 我们经常会用到多线程&#xff0c;这时候就需要纠结是使用 Qt 的 QThread 还是使用 C 标准库的 std::thread。 这里记录一下我自己的理解&#xff0c;先介绍一下 QThread 和 std::thread 的使用方法&#xff0c;对比一下他们的不同&#xff0c;最后说一下…...

LeetCode 算法:组合总和 c++

原题链接&#x1f517;&#xff1a;组合总和 难度&#xff1a;中等⭐️⭐️ 题目 给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target &#xff0c;找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 &#xff0c;并以列表形式返回。你可以按 …...

【两大3D转换SDK对比】HOOPS Exchange VS. CAD Exchanger

在现代工业和工程设计领域&#xff0c;CAD数据转换工具是确保不同软件系统间数据互通的关键环节。HOOPS Exchange和CAD Exchanger是两款备受关注的工具&#xff0c;它们在功能、支持格式、性能和应用场景等方面有着显著差异。 本文将从背景、支持格式、功能和性能、应用场景等…...

Openerstry + lua + redis根据请求参数实现动态路由转发

文章目录 一、需求分析二、准备1、软件安装2、redis-lua封装优化 三、实现1、nginx.conf2、dynamic.lua注意 3、准备两个应用4、访问nginx 四、参数直接传要代理的地址端口 一、需求分析 根据用户访问url的参数&#xff0c;将请求转发到对应指定IP的服务器上。 二、准备 1、…...

数字名片-Pushmall 智能AI数字名片7月更新计划

[数字名片]-商务营销推广助手7月更新计划 数字名片-商务营销推广助手7月更新计划 **2024年 6月完成模块开发优化****实现SaaS框架业务 1、智能名片&#xff1a;创建个人名片、企业名片、商机管理。 2、人脉商圈&#xff1a;附近人脉、就近群脉、好友名片。 3、企微社群&…...

21. Python代码快速查看数组分布

1. 前言 当你已经具备一段可用于快速查看数组分布的Python代码时,你拥有了一项强大的工具来分析和理解你的数据集。这种类型的代码通常会使用可视化库,例如Matplotlib和Seaborn,以直观的方式展示数据分布。这些库允许你创建直方图以观察数据集中的频率分布,以及核密度估计…...

记录些Redis题集(3)

分布式锁 分布式锁是一种用于在分布式系统中实现互斥访问的机制&#xff0c;它可以确保在多个节点、或进程同时访问共享资源。如果没有适当的锁机制&#xff0c;就可能导致数据不一致或并发冲突的问题。 分布式锁需要的介质 需要一个多个微服务节点都能访问的存储介质&#…...

OracleLinux6.9升级UEK内核

方法一: [root@localhost ~]# uname -r 4.1.12-61.1.28.el6uek.x86_64 [root@localhost ~]# rpm -qa | grep kernel-uek kernel-uek-firmware-4.1.12-61.1.28.el6uek.noarch kernel-uek-4.1.12-61.1.28.el6uek.x86_64 [root@localhost ~]# yum list kernel-uek Loaded plug…...

React学习笔记03-----手动创建和运行

一、项目创建与运行【手动】 react-scripts集成了webpack、bable、提供测试服务器 1.目录结构 public是静态目录&#xff0c;提供可以供外部直接访问的文件&#xff0c;存放不需要webpack打包的文件&#xff0c;比如静态图片、CSS、JS src存放源码 &#xff08;1&#xff09…...

ubantu22.04安装OceanBase 数据库

1、管理员启动cmd,运行 sudo bash -c "$(curl -s https://obbusiness-private.oss-cn-shanghai.aliyuncs.com/download-center/opensource/service/installer.sh)" 2、提示如下代表安装完成 3、修改数据库配置文件的密码 sudo vim /etc/oceanbase.cnf 然后保存退…...

【linux】【深度学习】fairseq框架安装踩坑

直接pip install fairseq发现跑代码时候老是容易崩&#xff0c;所以选择用源码编译安装。 python环境选择3.8以上都行&#xff0c;我选择3.10 首先安装torch&#xff0c; 我选择安装pip install torch1.13.1 torchaudio0.13.1以及cuda 11.7 &#xff08;具体cuda根据个人显卡进…...

【Python爬虫教程】第7篇-requests模块的cookies保存和使用

文章目录 为什么要保存cookiesrequests.utils工具类保存cookies到本地文件从本地文件解析cookies使用使用实践 为什么要保存cookies 保存cookies是避免每次都登录获取权限&#xff0c;一遍权限是有过期时间的&#xff0c;不需要每次重复登录&#xff0c;可以将cookies保存起来…...

微信小程序开发基础知识6----使用npm包

一、小程序对npm的支持与限制 目前&#xff0c;小程序中已经支持使用 npm 安装第三方包&#xff0c;从而来提高小程序的开发效率。但是&#xff0c;在小程序中使用npm 包有如下3个限制: ① 不支持依赖于 Node.js 内置库的包 ② 不支持依赖于浏览器内置对象的包 ③ 不支持依赖于…...

如何在element中table的 v-for中 使用slot-scope?

有时候我们需要通过数据库来动态控制表格的列,这样做的好处就是系统中如果有太多的表格项的话,直接这套代码就能通用了,其他的数据库里控制就行,不要太方便了,特别是一些ERP或者供应链的表格,动不动就是几十上百个字段,这时候不要太轻松了,废话不多说,直接上代码: &…...

企业网络实验dhcp-snooping、ip source check,防非法dhcp服务器、自动获取ip(虚拟机充当DHCP服务器)、禁手动修改IP

文章目录 需求相关配置互通性配置配置vmware虚拟机&#xff08;dhcp&#xff09;分配IP服务配置dhcp relay&#xff08;dhcp中继&#xff09;配置dhcp-snooping&#xff08;防非法dhcp服务器&#xff09;配置ip source check&#xff08;禁手动修改IP&#xff09;DHCP中继&…...

20. Python读取.mat格式文件通用函数

1. 前言 在科研和工程领域,MATLAB的.mat文件是一种常见的数据存储格式,用于保存复杂的数组和结构体。Python作为一种强大的编程语言,提供了多种库来读取和处理.mat文件。本文将介绍一个通用的Python函数,用于读取.mat格式文件,并将其内容转换为Python数据结构,以便进一步…...

Cypress UI自动化之安装环境

注&#xff1a;macOS系统 一、git环境 略 二、node环境 1、安装nvm 前提&#xff1a;有装过Homebrew&#xff0c;参考adb使用方法文档 1、安装nvm&#xff1a;首先要保证之前没有安装过node&#xff0c;如果之前安装过&#xff0c;先 brew uninstall node brew install n…...

SpringApplication.java类

Tips: 以下内容根据源码中的注解翻译 SpringApplication SpringApplication可用来从一个Java main方法引导和启动一个Spring应用。默认情况下&#xff0c;SpringApplication按照以下步骤引导你的应用&#xff1a; 创建一个合适的ApplicationContext&#xff08;依赖于你的cl…...

springboot 百货中心供应链管理系统小程序

一、前言 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;百货中心供应链管理系统被用户普遍使用&#xff0c;为方…...

【Java学习笔记】Arrays类

Arrays 类 1. 导入包&#xff1a;import java.util.Arrays 2. 常用方法一览表 方法描述Arrays.toString()返回数组的字符串形式Arrays.sort()排序&#xff08;自然排序和定制排序&#xff09;Arrays.binarySearch()通过二分搜索法进行查找&#xff08;前提&#xff1a;数组是…...

HBuilderX安装(uni-app和小程序开发)

下载HBuilderX 访问官方网站&#xff1a;https://www.dcloud.io/hbuilderx.html 根据您的操作系统选择合适版本&#xff1a; Windows版&#xff08;推荐下载标准版&#xff09; Windows系统安装步骤 运行安装程序&#xff1a; 双击下载的.exe安装文件 如果出现安全提示&…...

Web 架构之 CDN 加速原理与落地实践

文章目录 一、思维导图二、正文内容&#xff08;一&#xff09;CDN 基础概念1. 定义2. 组成部分 &#xff08;二&#xff09;CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 &#xff08;三&#xff09;CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 &#xf…...

Go 语言并发编程基础:无缓冲与有缓冲通道

在上一章节中&#xff0c;我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道&#xff0c;它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好&#xff0…...

人机融合智能 | “人智交互”跨学科新领域

本文系统地提出基于“以人为中心AI(HCAI)”理念的人-人工智能交互(人智交互)这一跨学科新领域及框架,定义人智交互领域的理念、基本理论和关键问题、方法、开发流程和参与团队等,阐述提出人智交互新领域的意义。然后,提出人智交互研究的三种新范式取向以及它们的意义。最后,总结…...

Caliper 配置文件解析:fisco-bcos.json

config.yaml 文件 config.yaml 是 Caliper 的主配置文件,通常包含以下内容: test:name: fisco-bcos-test # 测试名称description: Performance test of FISCO-BCOS # 测试描述workers:type: local # 工作进程类型number: 5 # 工作进程数量monitor:type: - docker- pro…...

Spring Security 认证流程——补充

一、认证流程概述 Spring Security 的认证流程基于 过滤器链&#xff08;Filter Chain&#xff09;&#xff0c;核心组件包括 UsernamePasswordAuthenticationFilter、AuthenticationManager、UserDetailsService 等。整个流程可分为以下步骤&#xff1a; 用户提交登录请求拦…...

vue3 daterange正则踩坑

<el-form-item label"空置时间" prop"vacantTime"> <el-date-picker v-model"form.vacantTime" type"daterange" start-placeholder"开始日期" end-placeholder"结束日期" clearable :editable"fal…...

阿里云Ubuntu 22.04 64位搭建Flask流程(亲测)

cd /home 进入home盘 安装虚拟环境&#xff1a; 1、安装virtualenv pip install virtualenv 2.创建新的虚拟环境&#xff1a; virtualenv myenv 3、激活虚拟环境&#xff08;激活环境可以在当前环境下安装包&#xff09; source myenv/bin/activate 此时&#xff0c;终端…...