C++实现进程调度模拟程序——哲学家进餐问题

简介: C++实现进程调度模拟程序——哲学家进餐问题

一、开发环境

开发平台: Visual C++6.0

开发环境: Windows XP

开发语言: C语言+API(windows应用程序编程接口)

二、进餐问题

一个圆桌上有一大碗面,5个盘子,5把筷子,5个座位上可以座5个哲学家,当哲学家就坐以后,其左右有且仅有一个筷子,每个筷子左又有且仅有一个哲学家。哲学家动作:思考,取筷(需要两个),取面,吃面。现设计一个礼仪以允许他们就餐,需要避免两个哲学家“抢”同一把筷子,又要避免饥饿和死锁

三、系统分析

  1. 互斥解决。每一把筷子使用一个2元信号量,只有获得信号量的哲学家才能使用筷子,从而避免对筷子的“抢夺”。
  2. 死锁和饥饿解决。餐厅只允许最多4名哲学家进入,因为总有一个哲学家可以得到两把筷子,从而可以正常就餐,因此不会有死锁出现。每为哲学家就餐完毕后,立即离开,放下筷子,以便没有用餐的哲学家可以使用,这也能保证不会有饥饿的存在了。
  3. 就餐顺序随机。为了较真实地模拟现实就餐问题,哲学家每次进入餐厅的顺序总是随机的,这个随机顺序在哲学家开始进入之间通过一个函数产生(这个过程会花一定时间)。
  4. 哲学家的各种状态
    位置空闲:当哲学家没有就座的时候,该位置显示空闲状态。
    思考等待:当一个哲学家进入餐厅但是没有获得餐具就餐的时候,进入思考等待状态。
    就餐:哲学家获得餐具后开始就餐进入就餐状态(就餐时间8000ms)。
    离开:哲学家就餐完毕就到了离开状态。
  5. 每个哲学家的就餐过程通过一个线程函数的调用来实现。

四、程序流程图

五、源代码

5.1 多线程实现

代码如下:

// 解决哲学家就餐问题
// 每个哲学家可用一个线程来模拟。
// 设有5个哲学家,5只筷子,每个哲学家吃饭时间为一个随机值,哲学家吃饭后的思考时间也是一个随机值。
#include <Windows.h>
#include <iostream>
#include <cstdio>
#include <stdlib.h>
#include <time.h>
/*
(1)奇数号的哲学家先拿起右边的筷子再拿起左边的筷子。
(2)偶数号哲学家先拿起左边的筷子,再拿起右边的筷子。
(3)如果哲学家抢到一只筷子,在抢占另一只筷子时失败,则要放弃已经抢占到的资源。
(4)左右两边都抢到筷子的哲学家,吃完放后释放资源。*/
using namespace std;
HANDLE chop[5];
HANDLE ph[5];
HANDLE mutex;
int nums = 0;
int random()
{
  return rand() % 100 + 20;
}
void eating(int id)
{
  int num = random();
  Sleep(num);
  printf("\t\t\t哲学家%d号吃了%d秒\n", id, num);
}
DWORD WINAPI phthread(LPVOID param) {
  nums++;
  int id = nums;
  int lc = id - 1;
  int rc = id % 5;
  int times = 0;
  int ret1, ret2;
  while (true)
  {
    Sleep(100);
    if (times >= 2)
      break;
    if (id % 2 == 0)
    {
      ret1 = WaitForSingleObject(chop[lc], 0);
      if (ret1 == WAIT_OBJECT_0)
      {
        ret2 = WaitForSingleObject(chop[rc], 0);
        if (ret2 == WAIT_OBJECT_0)
        {
          WaitForSingleObject(mutex, INFINITE);
          printf("哲学家%d号拿到两只筷子开始吃第%d顿饭。\n", id, times + 1);
          ReleaseMutex(mutex);
          times++;
          WaitForSingleObject(mutex, INFINITE);
          eating(id);
          ReleaseMutex(mutex);
          WaitForSingleObject(mutex, INFINITE);
          printf("\t\t\t哲学家%d号吃完两顿饭啦,放下筷子。\n", id);
          ReleaseMutex(mutex);
          ReleaseSemaphore(chop[rc], 1, NULL);
        }
        ReleaseSemaphore(chop[lc], 1, NULL);
      }
    }
    else
    {
      ret1 = WaitForSingleObject(chop[rc], 0);
      if (ret1 == WAIT_OBJECT_0)
      {
        ret2 = WaitForSingleObject(chop[lc], 0);
        if (ret2 == WAIT_OBJECT_0)
        {
          WaitForSingleObject(mutex, INFINITE);
          printf("哲学家%d号拿到两只筷子开始吃%d顿饭。\n", id, times + 1);
          ReleaseMutex(mutex);
          times++;
          WaitForSingleObject(mutex, INFINITE);
          eating(id);
          ReleaseMutex(mutex);
          WaitForSingleObject(mutex, INFINITE);
          printf("\t\t\t哲学家%d号吃完两顿饭啦,放下筷子。\n", id);
          ReleaseMutex(mutex);
          ReleaseSemaphore(chop[lc], 1, NULL);
        }
        ReleaseSemaphore(chop[rc], 1, NULL);
      }
    }
    WaitForSingleObject(mutex, INFINITE);
    ReleaseMutex(mutex);
  }
  printf("=======哲学家%d吃饱了然后离开了。=======\n", id);
  return 0;
}
int main()
{
  srand((unsigned)time(0));
  mutex = CreateMutex(NULL, false, NULL);
  for (int i = 0; i < 5; ++i)
  {
    chop[i] = CreateSemaphore(NULL, 1, 1, NULL);
  }
  for (int i = 0; i < 5; ++i)
  {
    int j = i + 1;
    ph[i] = CreateThread(NULL, 0, phthread, NULL, 0, NULL);
  }
  Sleep(10000); // 释放句柄
  for (int i = 0; i < 5; ++i)
  {
    CloseHandle(ph[i]);
    CloseHandle(chop[i]);
  }
  CloseHandle(mutex);
  Sleep(500);
  system("pause");
  return 0;
}

运行结果为:

5.2 C语言模拟

代码如下(不太好):

#include<iostream>
#include<stdlib.h>
#include<string>
#include<time.h>
#include<windows.h>
using namespace std;
int l = 0;
int w = 0;          //阻塞的进程个数,用来实现最多有四个哲学家同时拿筷子,避免死锁。
int s[5] = { 1,1,1,1,1 }; //筷子的信号量
int come_order[5] = { 0,0,0,0,0 };  // 就餐顺序
int wake[5] = { 0,0,0,0,0 };    // 阻塞唤醒顺序
int *q = wake;
int p(int*);
int v(int*);
int pro(int);//执行
int p(int *i)//p操作
{
  *i -= 1;
  if (*i < 0)
  {
    w++;
    return 1;
  }
  else return 0;
}
int v(int *i)
{
  *i += 1;
  if (*i <= 0) return 1;
  else return 0;
}
void eat(int i)
{
  cout << "第" << i << "位哲学家正在吃饭。" << endl;
  Sleep(3000);
}
int pro(int i)
{
  if (p(&s[i - 1]))
  {
    cout << "第" << i << "位哲学家请等待...." << endl;
    return 1;
  }
  if (p(&s[i]))
  {
    cout << "第" << i << "位哲学家请等待...." << endl;
    return 1;
  }
  eat(i);
  if (v(&s[i])) 
    *(q + i) = 1;
  if (v(&s[i - 1])) 
    *(q + i) = 1;
  cout << "第" << i << "位哲学家吃饱离开了。" << endl;
  return 0;
}
int get_rand() {//产生1到5之间的整数
  srand((unsigned)time(NULL));
  int RANGE_MIN = 1;
  int RANGE_MAX = 6;
  int randn = rand() % (RANGE_MAX - RANGE_MIN) + RANGE_MIN;
  return randn;
}
bool if_num_exist(int num) {
  for (int a = 0; a < 5; a++) {
    if (come_order[a] == num)
      return true;
  }
  return false;
}
void get_rand_order()
{//产生随机的进入顺序
  int temp = 0;
  bool tmp = 1;
  for (int a = 0; a < 5; a++)
  {
    while (tmp)
    {
      temp = get_rand();
      if (!if_num_exist(temp))
      {
        come_order[a] = get_rand();
        tmp = 0;
      }
    }
    tmp = 1;
  }
  cout << "饥饿顺序:" << come_order[0] << " " << come_order[1] << " " << come_order[2] << " " << come_order[3] << " " << come_order[4] << endl;
}
void get_order()
{
  int p[5];
  cout << "请输入五位哲学家的状态:" << endl << "                1表示饥饿,0表示思考。" << endl << "若有两个以上的哲学家同时饥饿,优先考虑小号的。" << endl;
  cin >> p[0] >> p[1] >> p[2] >> p[3] >> p[4];
  int a = 0;
  for (int k = 0; k < 5; k++)
  {
    if (p[k] == 1) come_order[a++] = k + 1;
  }
}
void main()
{
  int c;
  cout << "请选择进餐顺序生成方式,0表示随机生成,1表示手动输入:" << endl;
  cin >> c;
  if (c == 0) get_rand_order();
  else if (c == 1)  get_order();
  else { cout << "error" << endl; }
  while (w < 3)
  {
    for (int a = 0; a < 5; a++) { if (come_order[a] != 0) pro(come_order[a]); }
    for (int a = 0; a < 5; a++) { if (*(q + a) != 0) pro(*(q + a)); }
  }
}

运行结果为:


相关文章
|
1月前
|
算法 调度 UED
深入理解操作系统:进程调度与优先级队列
【10月更文挑战第31天】在计算机科学的广阔天地中,操作系统扮演着枢纽的角色,它不仅管理着硬件资源,还为应用程序提供了运行的环境。本文将深入浅出地探讨操作系统的核心概念之一——进程调度,以及如何通过优先级队列来优化资源分配。我们将从基础理论出发,逐步过渡到实际应用,最终以代码示例巩固知识点,旨在为读者揭开操作系统高效管理的神秘面纱。
|
22天前
|
存储 算法 调度
深入理解操作系统:进程调度的奥秘
在数字世界的心脏跳动着的是操作系统,它如同一个无形的指挥官,协调着每一个程序和进程。本文将揭开操作系统中进程调度的神秘面纱,带你领略时间片轮转、优先级调度等策略背后的智慧。从理论到实践,我们将一起探索如何通过代码示例来模拟简单的进程调度,从而更深刻地理解这一核心机制。准备好跟随我的步伐,一起走进操作系统的世界吧!
|
19小时前
|
Java Linux API
[JavaEE]———进程、进程的数据结构、进程的调度
操作系统,进程任务,PCB,PID,内存指针,文件描述符表,进程的调度,并发编程,状态,优先级,记账信息,上下文
|
1月前
|
消息中间件 算法 调度
深入理解操作系统:进程管理与调度
操作系统是计算机系统的核心,负责管理和控制硬件资源、提供用户接口以及执行程序。其中,进程管理是操作系统的重要组成部分,它涉及到进程的创建、调度、同步和通信等方面。本文将深入探讨进程管理的基本概念、进程调度算法以及进程间的同步和通信机制。通过本文的学习,读者将能够更好地理解操作系统的工作原理,并掌握进程管理的基本技能。
48 11
|
28天前
|
算法 调度 UED
深入理解操作系统:进程管理与调度策略
操作系统作为计算机系统的核心,其进程管理和调度策略对于系统性能和用户体验至关重要。本文将通过直观的代码示例和浅显易懂的语言,带领读者了解操作系统如何有效管理进程以及常见的进程调度算法。我们将从进程的基本概念出发,逐步深入到进程状态、进程控制块(PCB)的作用,最后探讨不同的调度算法及其对系统性能的影响。无论您是初学者还是有一定基础的开发者,都能从中获得有价值的信息。
|
27天前
|
负载均衡 算法 调度
深入理解操作系统:进程管理与调度
在数字世界的心脏,操作系统扮演着至关重要的角色。它如同一位精明的指挥家,协调着硬件资源和软件需求之间的和谐乐章。本文将带你走进操作系统的核心,探索进程管理的艺术和调度策略的智慧。你将了解到进程是如何创建、执行和消亡的,以及操作系统如何巧妙地决定哪个进程应该在何时获得CPU的青睐。让我们一起揭开操作系统神秘的面纱,发现那些隐藏在日常计算背后的精妙机制。
|
29天前
|
调度 开发者
深入理解操作系统之进程调度
在计算机科学领域,操作系统是核心的一环,它管理着计算机硬件资源,并提供接口供上层软件运行。本文将通过深入浅出的方式,探讨操作系统中至关重要的一个概念——进程调度。我们将从基础理论出发,逐步展开讲解进程调度的原理和实现,并配以实际代码示例,旨在帮助读者更好地理解和掌握这一主题。文章不仅适合初学者建立基础,也适合有一定基础的开发者深化理解。
|
1月前
|
算法 调度 UED
深入理解操作系统:进程管理与调度策略
【10月更文挑战第40天】在数字世界中,操作系统是连接硬件与软件的桥梁,它管理着计算机资源和提供用户服务。本文将深入探讨操作系统中的进程管理与调度策略,揭示它们如何协调多任务运行,保证系统高效稳定运作。通过代码示例,我们将展示进程创建、执行以及调度算法的实际应用,帮助读者构建对操作系统核心机制的清晰认识。
|
1月前
|
算法 调度 UED
深入理解操作系统:进程管理与调度策略
【10月更文挑战第34天】本文旨在探讨操作系统中至关重要的一环——进程管理及其调度策略。我们将从基础概念入手,逐步揭示进程的生命周期、状态转换以及调度算法的核心原理。文章将通过浅显易懂的语言和具体实例,引导读者理解操作系统如何高效地管理和调度进程,保证系统资源的合理分配和利用。无论你是初学者还是有一定经验的开发者,这篇文章都能为你提供新的视角和深入的理解。
44 3
|
1月前
|
算法 Linux 调度
深入理解操作系统之进程调度
【10月更文挑战第31天】在操作系统的心脏跳动中,进程调度扮演着关键角色。本文将深入浅出地探讨进程调度的机制和策略,通过比喻和实例让读者轻松理解这一复杂主题。我们将一起探索不同类型的调度算法,并了解它们如何影响系统性能和用户体验。无论你是初学者还是资深开发者,这篇文章都将为你打开一扇理解操作系统深层工作机制的大门。
39 0