哲学家就餐问题实现--多线程同步(unix - windows)

操作系统进程管理实战:从CPU调度到死锁排查,解决程序无法运行与资源占用问题 进程是操作系统进行资源分配和调度的基本单位,理解其管理机制是解决各类软件运行问题的关键。进程管理的核心原理在于操作系统通过进程控制块(PCB)记录进程状态,并利用调度算法(如时间片轮转、多级反馈队列)在有限的CPU核心上高效、公平地分配执行时间。这一机制的技术价值在于支撑了现代计算机的并发执行能力,使得多个程序能够“同时”运行。在实际应用场景中,无论是处理“程序无法运行”的平台兼容性问题,还是排查“baidunetdiskunite”等高资源占用进程,亦或是分析与解除数据库死锁,都依赖于对进程创建、调度、同 阅读详情

假设有 5 个哲学家,有 5 把叉子,每个哲学家有思考,饥饿,和吃饭三个状态。我们用 5 个信号量分别表示 5 把叉子
一. windows实现

源代码如下:

// PhilosopherDining.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "windows.h"

#include <process.h>
#include <time.h>
#include <stdlib.h>
#include <stdio.h>

#include <iostream>

using namespace std;

const unsigned int PHILOSOPHER_NUM=5;
const char THINKING=1;
const char HUNGRY=2;
const char DINING=3;

// each fork has a semaphore
HANDLE semph[PHILOSOPHER_NUM];

// Mutex for printing
HANDLE mutex;

void philosopherProc(void* param);

int main(int argc, char* argv[])
{
 int i;
 srand(time(0));

 mutex = CreateMutex(NULL, false, NULL);
 for (i=0; i<PHILOSOPHER_NUM; i++)
 {
  semph[i] = CreateSemaphore(NULL, 1, 1, NULL);
  _beginthread(philosopherProc, 0, (void*)&i);
  Sleep(10);
 }

 Sleep(2000);
 return 0;
}

void philosopherProc(void* param)
{
 int myid;
 char idStr[128];
 char stateStr[128];
 char mystate;
 int ret;
 unsigned int leftFork;
 unsigned int rightFork;

 myid = *((int*)(param));
 itoa(myid, idStr, 10);

 //cout << "philosopher " << myid << " begin......" << endl;
 Sleep(10);

 // initial state is THINKING
 mystate = THINKING;
 leftFork = (myid) % PHILOSOPHER_NUM;
 rightFork = (myid + 1) % PHILOSOPHER_NUM;

 while (true)
 {
  switch(mystate)
  {
  case THINKING:
   // changing my state
   mystate = HUNGRY;
   strcpy(stateStr, "HUNGRY");
   break;

  case HUNGRY:
   strcpy(stateStr, "HUNGRY");
   // first test the left fork ...
   ret = WaitForSingleObject(semph[leftFork], 0);
   if (ret == WAIT_OBJECT_0)
   {
    // left fork is ok, take it up !
    // then test the right fork ...
    ret = WaitForSingleObject(semph[rightFork], 0);
    if (ret == WAIT_OBJECT_0)
    {
     // right fork is also ok !
     // changing my state
     mystate = DINING;
     strcpy(stateStr, "DINING");
    }
    else
    {
     // right fork is being used by others, so I must put down
     // the left fork.
     ReleaseSemaphore(semph[leftFork], 1, NULL);
    }
   }
   break;

  case DINING:
   // put down both the left and right fork
   ReleaseSemaphore(semph[leftFork], 1, NULL);
   ReleaseSemaphore(semph[rightFork], 1, NULL);

   // changing my state
   mystate = THINKING;
   strcpy(stateStr, "THINKING");
   break;
  }

  // print my state
  WaitForSingleObject(mutex, INFINITE);
  cout << "philosopher " << myid << " is : " << stateStr << endl;  
  ReleaseMutex(mutex);
  
  // sleep a random time : between 1 - 5 s
  int sleepTime;
  sleepTime = 1 + (int)(5.0*rand()/(RAND_MAX+1.0));
  Sleep(sleepTime*10);
 }
}

 二. linux实现

PhilosopherDining.cpp

#include <iostream>
#include <string>
#include <pthread.h>
#include <unistd.h>
#include <semaphore.h>

#include "RasUtil.h"

using namespace std;

const unsigned int PHILOSOPHER_NUM=5;
const char THINKING=1;
const char HUNGRY=2;
const char DINING=3;

// each fork has a semaphore
sem_t semph[PHILOSOPHER_NUM];

// Mutex for printing
pthread_mutex_t mutex;

void* philosopherProc(void* param);

int main(int argc, char* argv[])
{
 int i;
 srand(getpid());
 pthread_t philosopherThread[PHILOSOPHER_NUM];
 int phId[PHILOSOPHER_NUM];

 pthread_mutex_init(&mutex, NULL);
 for (i=0; i<PHILOSOPHER_NUM; i++)
 {
         phId[i] = i;
  sem_init(&semph[i], 0, 1);
  pthread_create(&philosopherThread[i], NULL, philosopherProc, (void*)(&phId[i]));
  usleep(50);
 }

 sleep(3);
 return 0;
}

void* philosopherProc(void* param)
{
 int myid;
 char idStr[128];
 char stateStr[128];
 char mystate;
 int ret;
 unsigned int leftFork;
 unsigned int rightFork;

 myid = *((int*)(param));
 RasUtil::intToStr(myid, idStr);
 
 cout << "philosopher " << myid << " begin......" << endl;
 //usleep(10);

 // initial state is THINKING
 mystate = THINKING;
 leftFork = (myid) % PHILOSOPHER_NUM;
 rightFork = (myid + 1) % PHILOSOPHER_NUM;

 while (true)
 {
  switch(mystate)
  {
  case THINKING:
   // changing my state
   mystate = HUNGRY;
   strcpy(stateStr, "HUNGRY");
   break;

  case HUNGRY:
   strcpy(stateStr, "HUNGRY");
   // first test the left fork ...
   ret = sem_trywait(&semph[leftFork]);
   if (ret == 0)
   {
    // left fork is ok, take it up !
    // then test the right fork ...
    ret = sem_trywait(&semph[rightFork]);
    if (ret == 0)
    {
     // right fork is also ok !
     // changing my state
     mystate = DINING;
     strcpy(stateStr, "DINING");
    }
    else
    {
     // right fork is being used by others, so I must put down
     // the left fork.
     sem_post(&semph[leftFork]);
    }
   }
   break;

  case DINING:
   // put down both the left and right fork
   sem_post(&semph[leftFork]);
   sem_post(&semph[rightFork]);

   // changing my state
   mystate = THINKING;
   strcpy(stateStr, "THINKING");
   break;
  }

  // print my state
  pthread_mutex_lock(&mutex);
  cout << "philosopher " << myid << " is : " << stateStr << endl;  
  pthread_mutex_unlock(&mutex);
  
  // sleep a random time : between 1 - 5 s
  int sleepTime;
  sleepTime = 1 + (int)(5.0*rand()/(RAND_MAX+1.0));
  usleep(sleepTime*10);
 }
}

RasUtil.h : 完成整数转换为字符串

#ifndef _RasUtil_h_
#define _RasUtil_h_

class RasUtil
{
public:
 static inline void intToStr(int i, char* str);


};


inline void RasUtil::intToStr(int i, char* str)
{
    int dec;
    int sign;
    char* p;

    p = ecvt(i, 10, &dec, &sign);
    strcpy(str, p);
    str[dec] = 0;
}

#endif

操作系统武汉理工大学2023-2024复习 武汉理工大学2023-2024第一学期操作系统课程复习,里边包含一些个人认为较重要的知识点,可能存在部分知识点不全的情况,仅供参考 阅读详情

相关推荐

计算机核心课程体系化复习:从数据库索引到网络协议,构建底层知识图谱

在计算机科学领域,理解核心系统原理是构建扎实技术根基的关键。数据库系统通过索引(如B+树)、事务(ACID)和查询优化等机制,在数据持久化、一致性与性能之间进行精妙权衡。操作系统作为资源管理者,通过进程调度、虚拟内存和文件系统抽象硬件,确保系统高效稳定运行。计算机网络则依赖分层协议栈(如TCP/IP),在应用层(HTTP/3)、传输层(可靠传输)和网络层(路由寻址)协同工作,实现端到端通信。这些基础概念共同构成了计算机系统的骨架,其原理广泛应用于后端开发、分布式系统和高性能计算等场景。本文以数据库B+树索引

weixin_34025151的博客 632

吉林大学操作系统实验六(同步机制——信号量集与哲学家就餐问题)

如果第(i-1)%5号哲学家和第(i+1)%5号哲学家总是至少有一个处于进食状态,则第i号哲学家将会被“饿死”。用fork()系统调用创建5个哲学家进程并使其并发执行,通过观察运行结果判断同步算法的正确性。:理解Linux系统中基于信号量集的同步机制,并使用该同步机制解决并发进程的同步问题。(原书代码中的while(1)改为了for(j,1-5)循环,否则会一直运行下去)编写5个哲学家的就餐活动,解决哲学家就餐时对叉子资源的申请和释放。:同步机制——信号量集与哲学家就餐问题。:1.定义5把叉子的信号量集。

m0_62844139的博客 732

信号量同步实验报告(哲学家进餐问题避免死锁的三种方法)

操作系统初学,关于信号量同步的实验报告,用三种方法避免哲学家进餐问题死锁,a:and信号量,b:控制进餐人数,c设置条件

Linux C多任务编程(线程篇3)

多线程中常见的哲学家就餐问题和读者写者问题的解决方法。

十里长街走马的博客 315

Pixhawk固定翼飞行控制实战:L1与TECS算法详解(附代码解析)

本文深入解析了Pixhawk飞控在固定翼无人机中的核心控制算法:L1导航与TECS总能量控制。通过剖析算法原理、代码实现与实战调参,帮助开发者解决航线跟踪振荡、高度速度不稳定等常见问题,实现精准稳定的自主飞行。

wine的专栏 742

避坑指南:Ubuntu 22.04上源码编译Autoware.universe(Humble版)的完整流程与常见错误修复

本文详细介绍了在Ubuntu 22.04上源码编译Autoware.universe(Humble版)的完整流程与常见错误修复方法。从环境准备、依赖安装到编译优化,提供了实用的避坑指南和解决方案,帮助开发者高效完成安装并避免常见问题。特别针对源码安装过程中的疑难杂症给出了具体修复建议。

weixin_33712987的博客 382

经典进程同步问题(二)——哲学家进餐问题

哲学家就餐问题详解(附完整代码):三种方案解决死锁问题

aimat2020的博客 8915

2023年全国青少年信息素养大赛C++编程初中组决赛真题+答案解析

2023年全国青少年信息素养大赛C++编程初中组决赛真题+答案解析

伶俐角少儿编程 817

操作系统原理:哲学家就餐经典问题

哲学家就相当于线程,叉子就相当于资源。每个线程需要获取特定的两个资源才可以执行“吃”操作。每个叉子只能被特定的两个线程访问,且访问叉子时是互斥的。假设数据结构设计一个信号量数组,5个元素代表5个叉子,每个信号量的初始值(最大值)为1 代表每个叉子只能被1个线程同时访问 ,即互斥。0号线程只能访问0号资源和1号资源,1号线程只能访问1号资源和2号资源......4号线程只能访问4号资源和0号资源。 那么有人这么设计,每个哲学家先拿右边的叉子,再拿左手边的叉子。如果无法同时拿起两个叉子就释放掉自己占用的...

superSmart_Dong的博客 1635

Android 12.0 SystemUI下拉状态栏定制化之隐藏下拉通知栏布局功能实现(二)

在12.0的系统定制化开发中,由于从12.0开始SystemUI下拉状态栏和11.0的变化比较大,所以可以说需要从新分析相关的SystemUI的 布局,然后做分析来实现不同的功能,今天就开始实现关于隐藏SystemUI下拉状态栏中的通知栏布局系列二,去掉下拉状态栏中 通知栏部分 白色的圆角背景

安卓兼职framework和app工程师的博客 1634

【异常】came as a complete surprise to me,IllegalArgumentException: The template string is not valid.

是Spring AI中用于生成提示词(prompt)的一个类。提示词对于与大语言模型交互至关重要,因为它们指导模型生成特定类型的响应。允许开发者创建包含占位符的模板字符串,并通过提供具体的值来填充这些占位符,从而动态地生成个性化的提示词。

奶爸的编程之路,也就一周冷个三天 746

并发程序设计需要掌握的知识点

有朋友问过我,怎样学习多线程编程,我总结了一下,列了一下知识点:1、synchronized2、Runnable、Thread、Thread.sleep、Thread.yield、Thread.join3、wait、notify、notifyAll(注意其中锁的获得和释放)4、Mutex、Semaphore5、BlockingQueue (十分有用,必须掌握)6、ThreadPool7、Execu...

weixin_34128839的博客 85

【调优】OpenClaw从零开始高阶调优之skill篇

本文详细解析了OpenClaw技能系统的核心机制。首先介绍了技能的分层加载逻辑,按照优先级从高到低依次为:工作区专属技能、全局共享技能、出厂自带技能和自定义路径技能。通过流程图展示了从扫描到注册的完整加载流程,并解释了同名技能覆盖规则。随后深入剖析了SKILL.md文件结构,包含YAML元数据定义技能属性和Markdown正文说明使用方法,以公众号写作技能为例展示了具体配置。文章还提供了技能优先级切换的实用技巧,帮助用户灵活管理不同版本的技能。

海兰 238

Python线程高阶应用:线程池、同步原语与并发编程实战

并发编程是现代软件开发中的核心概念,它允许程序同时执行多个任务,从而提升资源利用率和响应速度。其原理在于通过多线程或多进程技术,在单个或多个CPU核心上并行处理任务,尤其适用于I/O密集型场景,如网络请求、文件读写等。在Python中,尽管存在全局解释器锁(GIL)的限制,但通过合理运用多线程技术,依然能显著提升I/O密集型应用的吞吐量和用户体验。本文聚焦于Python线程的高阶用法,深入探讨如何通过线程池(ThreadPoolExecutor)优化资源管理,以及如何运用多种同步原语(如RLock、Sema

weixin_30859423的博客 381

深度学习论文: Cultivated Land Extraction from High-Resolution Remote Sensing Image

深度学习论文: Cultivated Land Extraction from High-Resolution Remote Sensing Image The Winning Solution to the iFLYTEK Challenge 2021 Cultivated Land Extraction from High-Resolution Remote Sensing Image PDF: https://arxiv.org/pdf/2202.10974.pdf PyTorch代码: https:

mingo_敏 3479

【Unity 实用工具篇】✨| 使用Fungus插件制作一个对话系统,简单好学易上手

今天带来的是Unity中一款简单易用的对话插件Fungus,它是一个免费的交互式的对话系统。 Fungus是Unity免费的一款开源的插件,它可以无代码的实现玩家与NPC之间的对话,并且支持本地化,对相机、Sprite及音乐音效的控制。 学会使用该插件就可以做一些对话剧情类的游戏了,还是非常好用的,下面就来学习一下Fungus具体怎么使用吧!

努力前行,总会成为自己心中的那道光 1万+

[导入]并发程序设计需要掌握的知识点

转载地址:http://www.blogjava.net/jobs/archive/2006/01/09/56179.html 有朋友问过我,怎样学习多线程编程,我总结了一下,列了一下知识点: 1、synchronized 2、Runnable、Thread、Thread.sleep、Thread.yield、Thread.join 3、wait、notify、notifyAll(注意其中...

killalllsd的专栏 252

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

操作系统复习提纲

期末周复习资料

m0_74871043的博客 603

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

国防科技大学操作系统课程精讲:进程管理、内存管理、文件系统与I/O设备

操作系统是计算机系统的核心软件,负责管理硬件资源、提供用户接口并确保程序高效运行。其核心原理包括进程调度、内存分配、文件存储和设备驱动等关键技术。理解操作系统原理对于提升系统性能、优化资源利用和保障程序稳定性具有重要价值,尤其在服务器管理、嵌入式开发和系统优化等场景中不可或缺。本文聚焦于国防科技大学权威课程,系统讲解进程管理中的调度算法与同步机制、内存管理中的分页与虚拟内存技术,以及文件系统和I/O设备管理的核心实现,帮助学习者构建完整的操作系统知识体系。

weixin_30940783的博客 339

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

System V信号量解决哲学家就餐问题

一、哲学家就餐问题: 五个哲学家围在一个圆桌就餐,每个人都必须拿起两根筷子才能用餐,当每个人都先拿起左筷子,等待右筷子的时候就会造成死锁。 解决方案仅当一个哲学家两边筷子都可用时才允许他拿筷子就餐。 二、代码: #include<stdio.h> #include<stdlib.h> #include<sys/ipc.h> #include&...

mazi的博客 1760

Linux系统信号量实验

一、实验目的通过select来实现I/O复用二、实验要求Tcp客户端连接的同时,实现来自服务端的echo三、实验过程及结果开启server端(./server)客户端进行连接,并输入要发送的内容,在客户端进行回显(./tcp_client):四、实验代码服务端://tcp_server.c #include &lt;stdio.h&gt; #include &lt;stdlib.h&gt; #...

JamPaan 943

经典同步问题(二)---哲学家就餐问题

哲学家就餐问题

sunny_ss12的专栏 1万+

南邮《操作系统A》期末复习 CH4:并发进程

其实,我只是把 PPT Ctrl+C、Ctrl+V 了一下(捂脸) 4.1 并发进程 4.1.1 顺序程序与并发进程 1)顺序程序 顺序程序: 指令或语句序列,体现了某种算法,所有程序是顺序的。 顺序环境: 在计算机系统中只有一个程序在运行,这个程序独占系统中所有资源,其执行不受外界影响。 2)顺序程序的特征 顺序性执行 封闭性,独占资源 确定性,即可再现性 3)并发进程 **并...

Wonz 2177

操作系统信号量和管程

1 背景 同步互斥回顾: 并发问题: 竞争条件(竞态条件) 多程序并发存在大量问题 同步 多线程共享公共数据的协调执行 包括互斥与条件同步 互斥: 在同一时间只有一个线程可以执行临界区 确保线程同步 需要高层次的编程抽象(如: 锁) 从底层硬件支持编译 2 信号量 信号量是抽象数据类型 信号量用一个整形(sem)表示, 具有两个原子操作 P(): sem减1, 如果sem < 0, 等待, 否则继续(condition->wait) V(): sem加1, 如果sem &

Michael__Wu的博客 897

操作系统3-进程相关(进程的同步与通信)

3 进程同步与通信 3.1 进程同步 3.1.1 进程同步的基本概念 进程之间的两种制约关系 间接相互制约关系(系统资源共享) 直接相互制约关系(进程间合作) 进程同步的主要任务是使并发执行的诸进程之间能有效地共享资源和相互合作,使执行的结果具有可再现性。 临界资源(critical resource):一段时间仅允许一个进程访问的资源。 临界资源可能是硬件,也可能是...

maniacxx的博客 1670

操作系统课程设计---实验九 基于信号量机制的并发程序设计

操作系统课程设计—实验九基于信号量机制的并发程序设计 实验九 基于信号量机制的并发程序设计 1、实验目的 (1) 回顾操作系统进程、线程的有关概念,针对经典的同步、互斥、死锁与饥饿问题进行并发 程序设计与实现。 (2) 理解互斥体对象,利用互斥与同步操作编写读者-写者问题的并发程序,加深对 P (即semWait)、V(即 semSignal)原语以及利用 P、V 原语进行进程间同步与互斥操作的理解。 (3) 理解 Linux 支持的信息量机制,利用 IPC 的信号量系统调用编程实现哲学家进餐问题。 2、设

陈陈不like的博客 2838
上一篇: 开源平台的高并发集群思考
下一篇: struct的对齐
linuxchen
博客等级 码龄24年 34粉丝 96原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值