操作系统实验报告


[TOC]

实验一 OS启动过程、进程的概念及cmd.exe中的命令等

1、 实验目的

  1. 了解计算机启动过程的原理。
    • CPU 加电后运行 BIOS 程序
    • BIOS 进行自检和初始化
    • BIOS 将磁盘引导扇区(MBR)加载到内存中
    • 跳转执行引导程序BOOT,boot.bin
    • 引导程序将Loader.bin加载到内存中
    • 跳转执行加载程序
    • 加载程序将Kernel.dll加载到内存中,并进入保护模式、启动分页机制(扩展内存可用),创建初始进程。
    • 调用内核入口点,开始执行内核,进入桌面
    • explorer.exe
  2. 计算机程序运行的机制
  3. 程序以进程的形式进入内存。
  4. 一般指令运行的过程:
  5. 取指周期:PC中存放现行指令的地址,该地址送到MAR并送至地址总线,由控制部件CU向存储器发出读命令,使对应MAR所指单元的内容(指令)经数据总线送至MDR,再送至IR,并由CU控制PC内容加1,形成下一条指令的地址。
  6. 中断周期:CU把保存程序断点的内存地址送到MAR,并送到地址总线上,由CU向存储器发出写命令,并PC的内容(程序断点)送到MDR,经数据总线存入存储器。CU还将中断服务程序的入口地址送到PC,为下一个指令周期的取指做准备。
  7. 创建进程、撤销进程原语程序fork()、exec()和exit()CreateProcess()和ExitProcess()

2、实验时间:2学时,分两次

3、实验任务:

  • 百度fork()、exec()和exit()源程序,写出它们的功能。
  • 验证:通过启动任务管理器(WIN+R-taskmgr,ctrl+shift+esc和ctrl+alt+delete)运行和撤销资源管理器:explorer.exe
  • 了解cmd.exe所拥有的内部和外部命令。通过WIN+R运行了解功能,简写几个命令!
  • 了解任务管理器中显示的当前运行的各个进程。了解它们的功能,简写几个进程!
  • 验证命令解释程序的运行。
  • 练习如何把U盘或移动硬盘的MBR分区转换成GPT分区。写出命令行。

4、实验过程:

实验一:百度fork()、exec()和exit()源程序,写出它们的功能

Fork():一个进程,包括代码、数据和分配给进程的资源。fork()函数通过系统调用创建一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同的事,但如果初始参数或者传入的变量不同,两个进程也可以做不同的事。 一个进程调用fork()函数后,系统先给新的进程分配资源,例如存储数据和代码的空间。然后把原来的进程的所有值都复制到新的新进程中,只有少数值与原来的进程的值不同。相当于克隆了一个自己。

Exec():exec有两个功能:

  1. 取代当前的shell,通过给出的命令程序。即命令执行完成后,会退出本shell。

    比如:exec ls

    在shell中执行ls,ls结束后不返回原来的shell中。

  2. 文件重定向,可以将文件的重定向看作是是shell程序的文件重定向 比如:比如 exec 5</dev/null;exec 5<&-

    exec 3>file 将写入fd3中的内容写入到file中

    exec 5<file 将file读入到fd5中

    exec 5<&- 关闭fd5

最后发现当前脚本中exec的功能是执行完spark的启动脚本后,就退出shell,所以导致脚本后面的的两个命令都没有执行,结尾用echo输出也没有任何内容打印。

最后的解决方法是删除exec,文件就可以正常打印了。

Exit():0表示正常退出其他表示非正常一般用-1表示

使用 exit函数,要包含头文件” stdlib.h”。。使用exit()时,可以不论main()的返回类型。

实验二:通过启动任务管理器运行和撤销资源管理器

### 实验三:了解cmd.exe所拥有的内部和外部命令

内部命令:我们可以直接在cmd下就可以执行的命令,例如:telnet、ftp、cd、等等,你可以在CMD下输入help进行查看

外部命令:就是cmd下不能直接运行的命令,(例如大家常用的nc)他需要在CMD下切换到他(NC)所在的目录你才能运行NC及NC的命令

img
windows资源管理器:
**屏幕上显示的东西除了文件数据之外的全都算是资源管理器,资源管理器分为2个概念,一个是可见的,如“我的电脑”打开之后看到的是文件目录,一种是后台管理,如“任务管理器”是用来管理系统内核拖管的程序进程,而这些都被称为是系统资源,管理它们的就是资源管理器了。**

实验四: 了解任务管理器中显示的当前运行的各个进程

火绒安全软件弹窗拦截程序:

应用程序 拦截广告的

Csrss: windows 的核心进程之一。

Idle:任务管理器看到显示99%占用率 表示目前还有99%的性能等待你使用。

转换分区的方法练习:

方法一:convert(文件系统修改命令)

语法:convert [Volume] /fs:ntfs

Convert将文件分配表 (FAT) 和 FAT32 卷转换为 NTFS 文件系统,而现有的文件和文件夹完好无损。被转换为 NTFS 文件系统的卷无法再转换回 FAT 或 FAT32。

方法二:

1. cmd
2. diskpart
3. listdisk
4. select disk=*
5. clean
6. convert GPT

会出现异常情况:除C,其他分区都显示不出来了。

解决方法 :重启

​ 运行:diskmgmt.msc

实验五 : 验证命令解释程序的运行

附一个命令解释程序的源程序:

一个命令解释程序:

#include<stdio.h>
#include<string.h>
void main()
{
    char mingling[15][15]= {"dir","cd","md","rd","cls","date","time","ren","cope","help","quit"};
    char ch[15];
    printf("Microsoft Windows XP [版本 5.1.2600]\n");
    printf("<c> 版权所有 1985-2001 Microsoft Corp.\n");
    printf("\nc:\\Users\\Administrator>");
    while(1)
    {
        gets(ch);//读入字符串
        if(strcmp(ch,mingling[0])==0)
        {
            printf("dir  内部命令 显示一个目录中的文件和子目录\n");
        }
        else if(strcmp(ch,mingling[1])==0)
        {
            printf("cd 内部命令 显示当前目录的名称或将其更改。\n");
        }
        else if(strcmp(ch,mingling[2])==0)
        {
            printf("md 内部命令 创建一个目录。\n");
        }
        else if(strcmp(ch,mingling[3])==0)
        {
            printf("rd 内部命令 删除目录。\n");
        }
        else if(strcmp(ch,mingling[4])==0)
        {
            printf("cls 内部命令 清除屏幕\n");
        }
        else if(strcmp(ch,mingling[5])==0)
        {
            printf("date 内部命令 显示或设置日期\n");
        }
        else if(strcmp(ch,mingling[6])==0)
        {
            printf("time 内部命令 内部命令显示或设置系统时间\n");
        }
        else if(strcmp(ch,mingling[7])==0)
        {
            printf("ren 内部命令 重新命名文件\n");
        }
        else if(strcmp(ch,mingling[8])==0)
        {
            printf("cope 内部命令 将至少一个文件复制到另一个位置\n");
        }
        else if(strcmp(ch,mingling[9])==0)
        {
            printf("dir 内部命令 显示一个目录中的文件和子目录\n");
            printf("cd 内部命令 显示当前目录的名称或将其更改。\n");
            printf("md 内部命令 创建一个目录。\n");
            printf("rd 内部命令 删除目录。\n");
            printf("cls 内部命令 清除屏幕\n");
            printf("date 内部命令 显示或设置日期\n");
            printf("time 内部命令 内部命令显示或设置系统时间\n");
            printf("ren 内部命令 重新命名文件\n");
            printf("cope 内部命令 将至少一个文件复制到另一个位置\n");
            printf("help 外部命令 提供Windows命令的帮助信息\n");
            printf("quit 外部命令 退出命令解释程序\n");
        }
        else if(strcmp(ch,mingling[10])==0)
            return;
        else
        {
            printf("你输入错误的信息,请重新输入:\n");
        }
    }
}

实验六:练习如何把U盘或移动硬盘的MBR分区转换成GPT分区

  1. diskpart(启动Diskpart程序)
  2. list disk (查看电脑中有哪些磁盘)
  3. select disk 0(选中编号为0的磁盘)
  4. clean(清除磁盘所有分区)
  5. convert gpt(将磁盘转换成GPT格式)
  6. list partition(查看当前磁盘分区情况)
  7. create partition efi size=100(默认大小为M)
  8. create partition msr size =128
  9. create partition primary size =102400(此处为你想设置C盘的大小)
  10. 两次输入exit

实验二 P、V算法

1、 实验目的

一、 Dekker算法

设有进程P0和P1,两者谁要访问临界区,就让对应的flag=true(例如P0要访问临界区,就让flag[0]=true),相当于“举手示意我要访问”。初始值为0表示一开始没人要访问

turn用于标识当前允许谁进入,turn=0则P0可进入,turn=1则P1可进入。

二、 Peterson算法:

Peterson算法是一个实现互斥锁的并发程序设计算法,可以控制两个线程访问一个共享的单用户资源而不发生访问冲突。Gary L. Peterson于1981年提出此算法

三、生产者和消费者问题。

(1)加深对进程概念的理解,明确进程和程序的区别。

(2)进一步理解同步关系的含义。

(3)验证用信号量机制实现进程互斥的方法。

(4) 验证用信号机制实现进程同步的方法。

四、 读者和写者算法

(1) 写者优先

(2) 读者优先

五、哲学家就餐算法

六、验证参考程序

七、 编写自己的程序

2、实验时间:4学时(2次)

3、实验任务:

(1)验证参考程序Java,观察程序运行的结果,理解信号量的作用,从运行结果中体现出三种同步情况。

(2)实现方法:多进程实现和多线程实现

(3)编写自己的程序(可用其他语言编写)

4、实验过程:

一、Dekker算法

P0的逻辑

do{
  flag[0] = true;// 首先P0举手示意我要访问
  while(flag[1])  // 看看P1是否也举手了
  {
    if(turn==1) // 如果P1也举手了,那么就看看到底轮到谁
    {
      flag[0]=false;// 如果确实轮到P1,那么P0先把手放下(让P1先)
      while(turn==1);// 只要还是P1的时间,P0就不举手,一直等
      flag[0]=true;// 等到P1用完了(轮到P0了),P0再举手
    }
    flag[1] = false; // 只要可以跳出循环,说明P1用完了,应该跳出最外圈的while
  }
  visit();// 访问临界区
  turn = 1;// P0访问完了,把轮次交给P1,让P1可以访问
  flag[0]=false;// P0放下手
}

P1的逻辑

do{
  flag[1] = true;// 先P1举手示意我要访问
  while(flag[0])  // 如果P0是否也举手了
  {
    if(turn==0) // 如果P0也举手了,那么久看看到底轮到谁
    {
      flag[1]=false;// 如果确实轮到P0,那么P1先把手放下(让P0先)
      while(turn==0);// 只要还是P0的时间,P1就不举手,一直等
      flag[0]=true;// 等到P0用完了(轮到P1了),P1再举手
    }
  }
  visit();// 访问临界区
  turn = 0;// P1访问完了,把轮次交给P0,让P0可以访问
  flag[1]=false;// P1放下手
}

实现方法:

#include<iostream>
using namespace std;
bool flag[2];
int turn;
void procedure0()
{
    while(true)
    {
        flag[0]=true;
        while(flag[1]==true)
        {
            if(turn==1)
            {
                flag[0]=false;
                while(turn==1)
                {
                    /*do nothing*/
                }
                flag[0]=true;
            }
        }
        /*critical section*/ ;
        turn=1;
        flag[0]=false;
        /*remainder section*/
    }
}
void procedure1()
{
    while(true)
    {
        flag[1]=true;
        while(flag[0]==true)
        {
            if(turn==0)
            {
                flag[1]=false;
                while(turn==0)
                {
                    /*do nothing*/
                }
                flag[1]=true;
            }
        }
        /*critical section*/ ;
        turn=0
             flag[1]=false;
        /*remainder section*/
    }
}
int main()
{
    flag[0]=flag[1]=0;
    turn=1;
    //先让P1运行
    /*start procedure0 and procedure1*/ ;
    return 0;
}

二、Peterson算法

boolean flag[2];
int turn;
void procedure0()
{
    while(true)
    {
        flag[0]=true;
        turn=1;
        while(flag[1]&&turn==1) /*若flag[1]为false,P0就进入临界区;若flag[1]为tureP0循环等待,只要P1退出临界区,P0即可进入*/
        {
            /* donothing*/
        }
        visit();/*访问临界区*/
        flag[0]=false;/*访问临界区完成,procedure0释放出临界区*/
        /*remainder section*/
    }
}
void procedure1()
{
    while(true)
    {
        flag[1]=true;
        turn=0;
        while(flag[0]&&turn==0)
        {
            /* donothing*/ ;
        }
        visit();/*访问临界区*/
        flag[1]=false;/*访问临界区完成,procedure1释放出临界区*/
        /*remainder section*/
    }
}
void main()
{
    flag[0]=flag[1]=false;
    /*start procedure0 and procedure1*/ ;
}

进程P0,一旦它设置flag[0]=true,则P1不能进入临界区。如果P1已经进入临界区,那么flag[1]=true,P0被阻塞不能进入临界区。

另一方面,互相阻塞也避免了。假设P0在while里被阻塞了,表示flag[1]为true且turn=1,则此时P1可以执行。

三、生产者和消费者问题

考虑有一些生产者和消费者进程,生产者进程生产信息并把它们放入缓冲池中,消费者从缓冲池中取走信息。生产者—消费者问题是相互合作的进程关系的一种抽象,如在输入时,输入进程是生产者,计算进程是消费者;而在输出时,则计算进程是生产者,打印进程是消费者。请使用信号量机制来解决生产者—消费者问题。

归结生产者和消费者之间的关系:

(1) 诸进程之间互斥访问缓冲池

(2) 缓冲池满时,生产者等待

(3) 缓冲池空时,消费者等待

package com.loan.entity;
public class Store
{
    private final int MAX_SIZE=2;//仓库总共可存放货物
    private int count=0;//当前仓库货物
    public synchronized void add() throws InterruptedException
    {
        while(count>=MAX_SIZE)
        {
            System.out.println("仓库已满");
            System.out.println(Thread.currentThread().getName()+"等待中。。。。");
            this.wait();
        }
        count++;
        System.out.println(Thread.currentThread().getName()+"存入仓库,当前货物数:"+count);
        this.notify();
    }
    public synchronized void remove() throws InterruptedException
    {
        while(count<=0)
        {
            System.out.println("仓库空了");
            System.out.println(Thread.currentThread().getName()+"等待中。。。。");
            this.wait();
        }
        count--;
        System.out.println(Thread.currentThread().getName()+"取出货物,当前货物数:"+count);
        this.notify();
    }
    public static void main(String[] args)
    {
        Store s=new Store();
        Thread producer1=s.new Producer(s);//成员内部类需通过对象访问
        Thread producer2=s.new Producer(s);
        Thread consumer1=s.new Consumer(s);
        Thread consumer2=s.new Consumer(s);
        producer1.setName("producer1");//利用Thread中的方法
        producer2.setName("producer2");
        consumer1.setName("consumer1");
        consumer2.setName("consumer2");
        producer1.start();
        producer2.start();
        consumer1.start();
        consumer2.start();
    }
    class Producer extends Thread
    {
        private Store store;
        Producer(Store s)
        {
            store=s;
        }
        public void run()
        {
            while(true)
            {
                try
                {
                    store.add();
                    Thread.sleep(10000);
                }
                catch (InterruptedException e)
                {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }
    class Consumer extends Thread
    {
        private Store store;
        Consumer(Store s)
        {
            store=s;
        }
        public void run()
        {
            while(true)
            {
                try
                {
                    store.remove();
                    Thread.sleep(15000);
                }
                catch (InterruptedException e)
                {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }
}

四、读者和写者算法

C程序:

代码中信号量解析:

设置五个信号量,分别是RWMutex, mutex1, mutex2, mutex3, wrt,两个全局整型变量writeCount, readCount

信号量mutex1在写者的进入区和退出区中使用,使得每次只有一个写者对其相应进入区或推出区进行操作,主要原因是进入区和退出区存在对变量writeCount的修改,每个写者其进入区中writeCount加1,退出区中writeCount减1。信号量RWMutex则是读者和写者两个之间的互斥信号量,保证每次只读或者只写。写者优先中,写者的操作应该优先于读者,则信号量一直被占用着,直到没有写者的时候才会释放,即当writeCount等于1的时候,申请信号量RWMutex,其余的写者无需再次申请,但是写者是不能同时进行写操作的,则需要设置一个信号量wrt来保证每次只有一个写者进行写操作,当写者的数量writeCount等于0的时候,则证明此时没有没有读者了,释放信号量RWMutex。信号量mutex2防止一次多个读者修改readCount。当readCount为1的时候,为阻止写者进行写操作,申请信号量wrt,则写者就无法进行写操作了。信号量mutex3的主要用处就是避免写者同时与多个读者进行竞争,读者中信号量RWMutex比mutex3先释放,则一旦有写者,写者可马上获得资源。

4.1 写者优先

# include <stdio.h>
# include <stdlib.h>
# include <time.h>
# include <sys/types.h>
# include <pthread.h>
# include <semaphore.h>
# include <string.h>
# include <unistd.h>
//semaphores
sem_t RWMutex, mutex1, mutex2, mutex3, wrt;
int writeCount, readCount;
struct data
{
    int id;
    int opTime;
    int lastTime;
};

//读者
void* Reader(void* param)
{
    int id = ((struct data*)param)->id;
    int lastTime = ((struct data*)param)->lastTime;
    int opTime = ((struct data*)param)->opTime;
    sleep(opTime);
    printf("Thread %d: waiting to read\n", id);
    sem_wait(&mutex3);
    sem_wait(&RWMutex);
    sem_wait(&mutex2);
    readCount++;
    if(readCount == 1)
        sem_wait(&wrt);
    sem_post(&mutex2);
    sem_post(&RWMutex);
    sem_post(&mutex3);
    printf("Thread %d: start reading\n", id);
    /* reading is performed */
    sleep(lastTime);
    printf("Thread %d: end reading\n", id);
    sem_wait(&mutex2);
    readCount--;
    if(readCount == 0)
        sem_post(&wrt);
    sem_post(&mutex2);
    pthread_exit(0);
}
//写者
void* Writer(void* param)
{
    int id = ((struct data*)param)->id;
    int lastTime = ((struct data*)param)->lastTime;
    int opTime = ((struct data*)param)->opTime;
    sleep(opTime);
    printf("Thread %d: waiting to write\n", id);
    sem_wait(&mutex1);
    writeCount++;
    if(writeCount == 1)
    {
        sem_wait(&RWMutex);
    }
    sem_post(&mutex1);
    sem_wait(&wrt);
    printf("Thread %d: start writing\n", id);
    /* writing is performed */
    sleep(lastTime);
    printf("Thread %d: end writing\n", id);
    sem_post(&wrt);
    sem_wait(&mutex1);
    writeCount--;
    if(writeCount == 0)
    {
        sem_post(&RWMutex);
    }
    sem_post(&mutex1);
    pthread_exit(0);
}
int main()
{
    //pthread
    pthread_t tid; // the thread identifier
    pthread_attr_t attr; //set of thread attributes
    /* get the default attributes */
    pthread_attr_init(&attr);
    //initial the semaphores
    sem_init(&mutex1, 0, 1);
    sem_init(&mutex2, 0, 1);
    sem_init(&mutex3, 0, 1);
    sem_init(&wrt, 0, 1);
    sem_init(&RWMutex, 0, 1);
    readCount = writeCount = 0;
    int id = 0;
    while(scanf("%d", &id) != EOF)
    {
        char role;		//producer or consumer
        int opTime;		//operating time
        int lastTime;	//run time
        stanf("%c%d%d", &role, &opTime, &lastTime);
        struct data* d = (struct data*)malloc(sizeof(struct data));
        d->id = id;
        d->opTime = opTime;
        d->lastTime = lastTime;
        if(role == 'R')
        {
            printf("Create the %d thread: Reader\n", id);
            pthread_create(&tid, &attr, Reader, d);
        }
        else if(role == 'W')
        {
            printf("Create the %d thread: Writer\n", id);
            pthread_create(&tid, &attr, Writer, d);
        }
    }
    sem_destroy(&mutex1);
    sem_destroy(&mutex2);
    sem_destroy(&mutex3);
    sem_destroy(&RWMutex);
    sem_destroy(&wrt);
    return 0;
}

4.2 读者优先

#include <windows.h>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <accctrl.h>
#include <time.h>
unsigned int readcount = 0;
bool p_ccontinue = true; //控制程序结束
HANDLE RSemaphore; //改变readcount值时互斥
HANDLE WSemaphore; //写互斥
DWORD WINAPI Writer(LPVOID); //写者线程
DWORD WINAPI Reader(LPVOID); //读者线程
int main()
{
    RSemaphore = CreateSemaphore(NULL,1,1,NULL);
    WSemaphore = CreateSemaphore(NULL,1,1,NULL);
    const unsigned short Writer_COUNT = 3;//写者数量
    const unsigned short Reader_COUNT = 8;//读者数量
    const unsigned short THREADS_COUNT = Writer_COUNT+Reader_COUNT;
    HANDLE hThreads[THREADS_COUNT]; //各线程的 handle
    DWORD writerID[Writer_COUNT]; //写者线程的标识符
    DWORD readerID[Reader_COUNT]; //读者线程的标识符
    srand(time(0));
    int writer_count = 0;
    int reader_count = 0;
    for(int i = 0; i < Writer_COUNT + Reader_COUNT; i++)
    {
        int ran = rand()%10;
        if((ran < 5) && (writer_count < Writer_COUNT))//Writer
        {
            hThreads[i]=CreateThread(NULL,0,Writer,NULL,0,&writerID[writer_count]);
            if (hThreads[i]==NULL) return -1;
            writer_count++;
        }
        else if((ran >= 5) && (reader_count < Reader_COUNT))//Reader
        {
            hThreads[i]=CreateThread(NULL,0,Reader,NULL,0,&readerID[reader_count]);
            if (hThreads[i]==NULL) return -1;
            reader_count++;
        }
        Sleep(500);//等待500ms
    }
    while(p_ccontinue)
    {
        if(getchar())  //按回车后终止程序运行
        {
            p_ccontinue = false;
        }
    }
    return 0;
}
//写者
DWORD WINAPI Writer(LPVOID lpPara)
{
    while(p_ccontinue)
    {
        printf("\n%d is waiting to write...\n",GetCurrentThreadId());
        WaitForSingleObject(WSemaphore,INFINITE);//P(w)在读或在写时,写者阻塞
        printf("\n**  writer %d got the control\n",GetCurrentThreadId());
        //write...
        printf("\n%d is writing...\n",GetCurrentThreadId());
        Sleep(1500);
        printf("\n--- %d have finished the writing\n",GetCurrentThreadId());
        ReleaseSemaphore(WSemaphore,1,NULL);//V(w)写完,唤醒阻塞的读者或写者
        return 0;//结束此线程
    }
    return 0;
}
//读者
DWORD WINAPI Reader(LPVOID lpPara)
{
    while(p_ccontinue)
    {
        printf("\n%d is waiting to read...\n",GetCurrentThreadId());
        WaitForSingleObject(RSemaphore,INFINITE);//P(x)临界区互斥,所有读者修改readcount
        readcount++;
        if(readcount == 1)//第一个读,要等已经在写的写者写完才可以开始读
            WaitForSingleObject(WSemaphore,INFINITE);//P(w)有写时,读者阻塞
        //同时读,故要在Read()之前V(x)
        ReleaseSemaphore(RSemaphore,1,NULL);//V(x)
        //read...
        printf("\n%d is reading...\n",GetCurrentThreadId());
        Sleep(1500);
        printf("\n--- %d have finished the reading\n",GetCurrentThreadId());
        WaitForSingleObject(RSemaphore,INFINITE);//P(x)
        readcount--;
        if(readcount== 0)
        {
            printf("\n----- All Readers done\n");
            ReleaseSemaphore(WSemaphore,1,NULL);//V(w)都不读,唤醒阻塞的写者
        }
        ReleaseSemaphore(RSemaphore,1,NULL);//V(x)
        return 0;//结束此线程
    }
    return 0;
}

五、哲学家就餐算法

#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <pthread.h>
#include <errno.h>
#include <math.h>
//筷子作为mutex
pthread_mutex_t chopstick[6] ;
void *eat_think(void *arg)
{
    char phi = *(char *)arg;
    int left,right; //左右筷子的编号
    switch (phi)
    {
    case 'A':
        left = 5;
        right = 1;
        break;
    case 'B':
        left = 1;
        right = 2;
        break;
    case 'C':
        left = 2;
        right = 3;
        break;
    case 'D':
        left = 3;
        right = 4;
        break;
    case 'E':
        left = 4;
        right = 5;
        break;
    }

    int i;
    for(;;)
    {
        usleep(3); //思考
        pthread_mutex_lock(&chopstick[left]); //拿起左手的筷子
        printf("Philosopher %c fetches chopstick %d\n", phi, left);
        if (pthread_mutex_trylock(&chopstick[right]) == EBUSY)  //拿起右手的筷子
        {
            pthread_mutex_unlock(&chopstick[left]); //如果右边筷子被拿走放下左手的筷子
            continue;
        }
        //	pthread_mutex_lock(&chopstick[right]); //拿起右手的筷子,如果想观察死锁,把上一句if注释掉,再把这一句的注释去掉
        printf("Philosopher %c fetches chopstick %d\n", phi, right);
        printf("Philosopher %c is eating.\n",phi);
        usleep(3); //吃饭
        pthread_mutex_unlock(&chopstick[left]); //放下左手的筷子
        printf("Philosopher %c release chopstick %d\n", phi, left);
        pthread_mutex_unlock(&chopstick[right]); //放下左手的筷子
        printf("Philosopher %c release chopstick %d\n", phi, right);

    }
}
int main()
{
    pthread_t A,B,C,D,E; //5个哲学家

    int i;
    for (i = 0; i < 5; i++)
        pthread_mutex_init(&chopstick[i],NULL);
    pthread_create(&A,NULL, eat_think, "A");
    pthread_create(&B,NULL, eat_think, "B");
    pthread_create(&C,NULL, eat_think, "C");
    pthread_create(&D,NULL, eat_think, "D");
    pthread_create(&E,NULL, eat_think, "E");
    pthread_join(A,NULL);
    pthread_join(B,NULL);
    pthread_join(C,NULL);
    pthread_join(D,NULL);
    pthread_join(E,NULL);
    return 0;
}

文章作者: 十二惊惶
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 十二惊惶 !
  目录