Linux多线程编程-哲学家就餐问题详解与实现(C语言)
在哲学家就餐问题中,假设有五位哲学家围坐在圆桌前,每位哲学家需要进行思考和进餐两种活动。他们的思考不需要任何资源,但进餐需要使用两根筷子(左右两侧各一根)。筷子是共享资源,哲学家们在进行进餐时需要竞争筷子,而且不能出现死锁情况,即每位哲学家都能在有可能的情况下进餐。
问题示例:
假设有五位哲学家,编号为 0 到 4,围坐在圆桌周围,每位哲学家面前有一根筷子。他们的行为可以描述如下:
-
思考:哲学家在没有筷子的时候,思考一段时间。
-
进餐:哲学家只有同时拿到左右两边的筷子才能进餐,进餐完成后放下筷子继续思考。

解决方案概述:
- 状态记录:每位哲学家有三种状态:思考、饥饿和进餐。
- 互斥保护:使用互斥锁保护对状态的访问,确保状态变化的原子性。
- 信号量:使用信号量控制每根筷子的使用,确保每位哲学家能同时拿到左右两根筷子。
我们用一个数组 state 来记录每一位哲学家的三个状态,分别是在进餐状态、思考状态、饥饿状态(正在试图拿叉子)。
那么,一个哲学家只有在两个邻居都没有进餐时,才可以进入进餐状态。
第 i 个哲学家的左邻右舍,则由宏 LEFT 和 RIGHT 定义:
- LEFT : ( i + 5 - 1 ) % 5
- RIGHT : ( i + 1 ) % 5
比如 i 为 2,则 LEFT 为 1,RIGHT 为 3。
解决步骤:
-
定义全局变量和初始化:
- 定义哲学家状态数组
state[],互斥锁pthread_mutex_t mutex和信号量数组sem_t chopsticks[]。 - 初始化互斥锁和每个筷子的信号量。
- 定义哲学家状态数组
-
哲学家线程函数设计:
- 哲学家线程循环执行思考和进餐过程。
- 在饥饿状态时,试图获取两侧筷子,获取成功则进餐,否则等待。
- 进餐后释放筷子,继续思考。
-
获取和释放筷子的操作:
- 使用互斥锁保护对状态数组的修改,确保线程安全。
- 利用信号量控制筷子的获取和释放,避免死锁和资源争夺。

示例代码:
#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语言)
在哲学家就餐问题中,假设有五位哲学家围坐在圆桌前,每位哲学家需要进行思考和进餐两种活动。他们的思考不需要任何资源,但进餐需要使用两根筷子(左右两侧各一根)。筷子是共享资源,哲学家们在进行进餐时需要…...
从C向C++18——演讲比赛流程管理系统
一.项目需求 1.比赛规则 学校举行一场演讲比赛,共有12个人参加。比赛共两轮,第一轮为淘汰赛,第二轮为决赛。每名选手都有对应的编号,如 10001~ 10012比赛方式:分组比赛,每组6个人;第一轮分为两…...
QThread和std::thread
在 Qt 中, 我们经常会用到多线程,这时候就需要纠结是使用 Qt 的 QThread 还是使用 C 标准库的 std::thread。 这里记录一下我自己的理解,先介绍一下 QThread 和 std::thread 的使用方法,对比一下他们的不同,最后说一下…...
LeetCode 算法:组合总和 c++
原题链接🔗:组合总和 难度:中等⭐️⭐️ 题目 给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 ,并以列表形式返回。你可以按 …...
【两大3D转换SDK对比】HOOPS Exchange VS. CAD Exchanger
在现代工业和工程设计领域,CAD数据转换工具是确保不同软件系统间数据互通的关键环节。HOOPS Exchange和CAD Exchanger是两款备受关注的工具,它们在功能、支持格式、性能和应用场景等方面有着显著差异。 本文将从背景、支持格式、功能和性能、应用场景等…...
Openerstry + lua + redis根据请求参数实现动态路由转发
文章目录 一、需求分析二、准备1、软件安装2、redis-lua封装优化 三、实现1、nginx.conf2、dynamic.lua注意 3、准备两个应用4、访问nginx 四、参数直接传要代理的地址端口 一、需求分析 根据用户访问url的参数,将请求转发到对应指定IP的服务器上。 二、准备 1、…...
数字名片-Pushmall 智能AI数字名片7月更新计划
[数字名片]-商务营销推广助手7月更新计划 数字名片-商务营销推广助手7月更新计划 **2024年 6月完成模块开发优化****实现SaaS框架业务 1、智能名片:创建个人名片、企业名片、商机管理。 2、人脉商圈:附近人脉、就近群脉、好友名片。 3、企微社群&…...
21. Python代码快速查看数组分布
1. 前言 当你已经具备一段可用于快速查看数组分布的Python代码时,你拥有了一项强大的工具来分析和理解你的数据集。这种类型的代码通常会使用可视化库,例如Matplotlib和Seaborn,以直观的方式展示数据分布。这些库允许你创建直方图以观察数据集中的频率分布,以及核密度估计…...
记录些Redis题集(3)
分布式锁 分布式锁是一种用于在分布式系统中实现互斥访问的机制,它可以确保在多个节点、或进程同时访问共享资源。如果没有适当的锁机制,就可能导致数据不一致或并发冲突的问题。 分布式锁需要的介质 需要一个多个微服务节点都能访问的存储介质&#…...
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是静态目录,提供可以供外部直接访问的文件,存放不需要webpack打包的文件,比如静态图片、CSS、JS src存放源码 (1)…...
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发现跑代码时候老是容易崩,所以选择用源码编译安装。 python环境选择3.8以上都行,我选择3.10 首先安装torch, 我选择安装pip install torch1.13.1 torchaudio0.13.1以及cuda 11.7 (具体cuda根据个人显卡进…...
【Python爬虫教程】第7篇-requests模块的cookies保存和使用
文章目录 为什么要保存cookiesrequests.utils工具类保存cookies到本地文件从本地文件解析cookies使用使用实践 为什么要保存cookies 保存cookies是避免每次都登录获取权限,一遍权限是有过期时间的,不需要每次重复登录,可以将cookies保存起来…...
微信小程序开发基础知识6----使用npm包
一、小程序对npm的支持与限制 目前,小程序中已经支持使用 npm 安装第三方包,从而来提高小程序的开发效率。但是,在小程序中使用npm 包有如下3个限制: ① 不支持依赖于 Node.js 内置库的包 ② 不支持依赖于浏览器内置对象的包 ③ 不支持依赖于…...
如何在element中table的 v-for中 使用slot-scope?
有时候我们需要通过数据库来动态控制表格的列,这样做的好处就是系统中如果有太多的表格项的话,直接这套代码就能通用了,其他的数据库里控制就行,不要太方便了,特别是一些ERP或者供应链的表格,动不动就是几十上百个字段,这时候不要太轻松了,废话不多说,直接上代码: &…...
企业网络实验dhcp-snooping、ip source check,防非法dhcp服务器、自动获取ip(虚拟机充当DHCP服务器)、禁手动修改IP
文章目录 需求相关配置互通性配置配置vmware虚拟机(dhcp)分配IP服务配置dhcp relay(dhcp中继)配置dhcp-snooping(防非法dhcp服务器)配置ip source check(禁手动修改IP)DHCP中继&…...
20. Python读取.mat格式文件通用函数
1. 前言 在科研和工程领域,MATLAB的.mat文件是一种常见的数据存储格式,用于保存复杂的数组和结构体。Python作为一种强大的编程语言,提供了多种库来读取和处理.mat文件。本文将介绍一个通用的Python函数,用于读取.mat格式文件,并将其内容转换为Python数据结构,以便进一步…...
Cypress UI自动化之安装环境
注:macOS系统 一、git环境 略 二、node环境 1、安装nvm 前提:有装过Homebrew,参考adb使用方法文档 1、安装nvm:首先要保证之前没有安装过node,如果之前安装过,先 brew uninstall node brew install n…...
SpringApplication.java类
Tips: 以下内容根据源码中的注解翻译 SpringApplication SpringApplication可用来从一个Java main方法引导和启动一个Spring应用。默认情况下,SpringApplication按照以下步骤引导你的应用: 创建一个合适的ApplicationContext(依赖于你的cl…...
【Linux驱动开发】第10天:设备树零基础入门——DTS/DTB/DTC全解+编译流程
目录 为什么需要设备树?传统驱动的终极痛点DTS/DTB/DTC 大白话定义核心区别三者关系完整编译流程图最简单的DTS示例语法解析设备树编译与反编译实操命令内核如何加载和使用设备树核心总结面试必背考点 1. 为什么需要设备树?传统驱动的终极痛点 在设备树…...
性价比高的国产PLM软件公司
在制造业领域,不少企业都面临着研发效率低下、协同困难等问题。比如某电子制造企业,研发部门与生产部门之间信息沟通不畅,图纸版本管理混乱,导致产品研发周期延长,生产成本增加,新品上市时间比预期晚了近30…...
计算机毕业设计 | SpringBoot+vue医院药品管理系统(附源码+论文)
1,绪论 1.1课题背景 身处网络时代,随着网络系统体系发展的不断成熟和完善,人们的生活也随之发生了很大的变化。目前,人们在追求较高物质生活的同时,也在想着如何使自身的精神内涵得到提升,而读书就是人们…...
scikit-learn自定义Pipeline:从接口契约到业务落地的完整实践
1. 项目概述:为什么需要自己动手定制 scikit-learn 的模型与流水线在真实的数据科学项目里,你几乎不可能靠from sklearn.ensemble import RandomForestClassifier一行代码就搞定所有事。我带过十几个工业级建模项目,从电商价格预测到医疗设备…...
都在喊难,它却狂赚!深度扒开长鑫科技底牌:什么才是决定生死的产业势?
2026年的商业世界,正在经历一场冰火两重天的考验。 一边,是无数传统企业在需求萎缩、价格内卷的泥潭里苦苦挣扎,老板们每天为了几毛钱的利润拼得头破血流;而另一边,一份堪称“核弹级”的财报,直接炸翻了整个…...
AI驱动的DNA分析平台:简化生物信息学流程
1. 项目概述:当生物信息学遇上“开箱即用”的AI逻辑引擎“BIOREASON”这个名字一出现,我就下意识在笔记本上画了个双螺旋和神经网络的交叉草图——不是为了炫技,而是因为过去八年里,我亲手调试过三十多套DNA分析流程,从…...
AI Agent与RPA的融合:智能自动化新范式
AI Agent与RPA的融合:智能自动化新范式 关键词:AI Agent、RPA、智能自动化、融合技术、自主决策、业务流程优化、人机协作 摘要:本文深入探讨了AI Agent与RPA(机器人流程自动化)的融合,揭示了这一技术组合如何开创智能自动化的新范式。我们将通过生动的类比和详细的技术解…...
蒙古语AI语音落地难?ElevenLabs最新v3.2模型支持率提升至98.7%,但90%开发者忽略这5个编码陷阱
更多请点击: https://intelliparadigm.com 第一章:蒙古语AI语音落地的现实困境与技术拐点 蒙古语作为中国少数民族语言中使用人口较多、语法高度黏着、音系复杂的阿尔泰语系代表,其AI语音技术长期受限于低资源特性——标准语音数据集不足50小…...
远程会议还在发文档改来改去?我用 Rustpad 搭了个协作平台彻底解决
前言 远程会议开到一半,需要共同修订一份文档或代码提纲,这种场景估计不少人经历过。方案来来去去就那几个:发邮件等反馈、微信来回传文件、用腾讯文档但要登录账号……每种都有各自的鸡肋之处。后来我自己琢磨出一套更顺手的方案࿱…...
用户分享 + 消费排队福利模式合规落地指南:5 大实体行业通用方案
注:本文所有数据为单门店经营案例参考,不代表所有门店的经营收益,实际效果受多种因素影响一、多数社区门店的经营困境:营销预算有限,获客留客难度大不少社区夫妻店的经营者,都会遇到类似的经营难题…...
