操作系统第四次实验:进程调度实验

前言

为了帮助同学们完成痛苦的实验课程设计,本作者将其作出的实验结果及代码贴至CSDN中,供同学们学习参考。如有不足或描述不完善之处,敬请各位指出,欢迎各位的斧正!

一、实验目的

  1. 熟悉PV操作的实现原理。
  2. 熟悉信号量机制。使用信号量机制模拟实现PV操作,从而控制多个进程对共享资源的使用。
  3. 通过在Linux中使用信号量进行进程同步和互斥的方法,进一步理解进程间同步与互斥、临界区与临界资源的概念与含义,并学会 Linux信号量的基本使用方法。

二、实验环境

实验机房软件Ubuntu和在VMware虚拟机上安装的Linux操作系统。

三、实验内容及步骤

本实验基本POSIX有名信号量实现(既可用于进程间同步,也可用于线程间同步),下面给出其介绍:

  1. sem_open:创建并初始化一个有名信号量,如该信号量已经存在,则打开它。
    (1)函数原型:sem_t* sem_open(const char *name, int oflag, mode_t mode, int value);
    (2)头文件:#include<semaphore.h>
    (3)参数:name: 文件名路径,如’mysem’,会创建/dev/shm/sem.mysem
    oflag:创建标志,有O_CREATE或O_CREATE | O_EXCL两个取值,O_CREATE表示信号量如存在,则打开之,如不存在,则创建;O_CREATE | O_EXCL表示信号量已存在,则返回error
    mode:信号量访问权限,如0666代表所有人可读写
    value:信号量初始化值
    (4)返回值:成功则返回信号量指针,出错则返回SEM_FAILED。
  2. sem_wait:测试指定信号量的值,相当于P操作。若信号量大于0,则减1立刻返回,如信号量值等于0,则阻塞直到信号量值大于0,此刻立即减1,然后返回。
    (1)函数原型:int sem_wait(sem_t *sem);
    (2)头文件:#include<semaphore.h>
    (3)参数:sem,要测试的信号量指针。
    (4)返回值:成功则返回0,出错则返回-1。
  3. sem_post:信号量值加1,相当于V操作。唤醒正在等待该信号量的某个进程或线程。
    (1)函数原型:int sem_post(sem_t *sem)
    (2)头文件:#include<semaphore.h>
    (3)参数:sem,要访问的信号量指针。
    (4)返回值:成功则返回0,出错返回-1。
  4. int sem_close(sem_t *sem):关闭有名信号量,进程中,如果使用完信号量,应使用该函数关闭有名信号量。
  5. int sem_unlink(const char *name):删除系统中的信号量,如果有任何进程/线程引用这个信号量,sem_unlink函数不会起到任何作用,即只有最后一个使用该信号量的进程来执行sem_unlink才有效。

1、编写一个C语言程序,进行10次循环,每个循环中,屏幕输出两次给定的字符。在使用互斥和不使用互斥的两种情况下,观察多个进程运行时的输出情况。
(1)使用gcc -o no_mutex no_mutex.c编译链接后生成目标代码,再使用./no_mutex&./no_mutex B运行,写出运行结果并分析。
在这里插入图片描述
(2)如下示例(with_sem.c)中,设置了一个信号量mutex,初始值为1,表示当前无人使用临界区,信号量使用完毕后,需要关闭,之后删除。使用gcc -o with_mutex with_mutex.c -lrt编译链接后生成目标代码,再使用./with_mutex &./with_mutex B运行,写出运行结果并分析。
在这里插入图片描述
(3)编写两个C语言black_chess.c以及red_chess.c,分别模拟下象棋过程中红方走子和黑方走子过程。走子规则:红先黑后,红、黑双方轮流走子,到第10步,红方胜,黑方输。
解题思路:设置以下两个同步信号量hei:初值1,代表黑方已经走子,轮到红方走子(满足“红先黑后”),hong:初值为0,代表红方尚未走子。
红方进程代码:red_chess.c如下,请编写出黑方代码black_chess.c
编译:gcc -o red_chess red_chess.c -lrt
gcc -o black_chess black_chess.c -lrt
运行:./red_chess&./black_chess
写出运行结果,并分析总结。
在这里插入图片描述

四、实验程序清单

  1. 控制台输入gcc -o no_mutex no_mutex.c进行编译
  2. 控制台输入./no_mutex&./no_mutex B运行
//no_mutex.c
#include<stdio.h>
#include<stdlib.h>
int main(int argc,char *argv[])
{
	char message='x';
	int i=0;
	if(argc>1)
	{
		message=argv[1][0];
	}
	for(i=0;i<10;i++)
	{
		printf("%c",message);
		fflush(stdout);
		sleep(rand()%3);
		printf("%c",message);
		fflush(stdout);
		sleep(rand()%2);
	}
	sleep(10);
	exit(0);
return 0;
}
  1. 控制台输入gcc -o with_mutex with_mutex.c -lrt -pthread进行编译
  2. 控制台输入./no_mutex&./no_mutex B运行
//with_mutex.c
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<semaphore.h>
#include<fcntl.h>
#include<sys/stat.h>
#include<unistd.h>
int main(int argc,char *argv[])
{
	char message='x';
	int i=0;
	if(argc>1)
	{
		message=argv[1][0];
	}
	sem_t *mutex=sem_open("mysem",O_CREAT,0666,1);
	for(i=0;i<10;i++)
	{
		sem_wait(mutex);		
		printf("%c",message);
		fflush(stdout);
		sleep(rand()%3);
		printf("%c",message);
		fflush(stdout);
		sem_post(mutex);
		sleep(rand()%2);
	}
	sleep(10);
printf("\n");
	sem_close(mutex);
	sem_unlink("mysem");
	exit(0);
	
return 0;
}
//red_chess.c
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<semaphore.h>
#include<fcntl.h>
#include<sys/stat.h>
int main(int argc,char *argv[])
{
	int i=0;
	sem_t *hei=sem_open("chess_black_sem",O_CREAT,0666,1);
	sem_t *hong=sem_open("chess_red_sem",O_CREAT,0666,0);
	for(i=0;i<10;i++)
	{
		sem_wait(hei);
		if(i!=9)
			{printf("Red chess had moved,black chess go!\n");}
		else
			{printf("Red chess win!!!\n");}
		fflush(stdout);
		sem_post(hong);
	}
	sleep(10);
	sem_close(hei);
	sem_close(hong);
	sem_unlink("chess_red_sem");
	sem_unlink("chess_black_sem");
	exit(0);
	return 0;
}
//black_chess.c
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<semaphore.h>
#include<fcntl.h>
#include<sys/stat.h>
int main(int argc,char *argv[])
{
	int i=0;
	sem_t *hei=sem_open("chess_black_sem",O_CREAT,0666,1);
	sem_t *hong=sem_open("chess_red_sem",O_CREAT,0666,0);
	for(i=0;i<10;i++)
	{
		sem_wait(hong);
		if(i!=9)
			{printf("Black chess had moved,red chess go!\n");}
		else
			{printf("Black chess win!!!\n");}
		fflush(stdout);
		sem_post(hei);
	}
	sleep(10);
	sem_close(hei);
	sem_close(hong);
	sem_unlink("chess_red_sem");
	sem_unlink("chess_black_sem");
	exit(0);
	return 0;
}
  1. 控制台分别输入gcc -o red_chess red_chess.c -lrt -pthreadgcc -o black_chess black_chess.c -lrt -pthread进行编译
  2. 控制台输入./red_chess&./black_chess运行

五、实验结果

在这里插入图片描述
分析:在不使用互斥的程序中,x和B的出现没有什么规律。(进程同步)
在这里插入图片描述
分析:在使用信号量来对临界资源进行互斥时,x和B以相同的数目交替出现。(进程互斥,进程交替执行)
在这里插入图片描述
分析:在使用信号量来对临界资源进行互斥时,红方与黑方以相同的次数(一次)交替出现、交替下棋(进程互斥,进程交替执行)

六、实验总结

  1. 用于实现同步、互斥的信号量都是成对出现的。实现互斥的信号量成对的P原语在V原语之前,实现同步的信号量成对的P原语在V原语之后。
  2. 同步执行的进程不会因制约关系而相互等待,所以可以无序执行;并发执行的进程因直接制约关系而需相互等待,相互合作,以实现各进程按相互协调的速度向前推进。
  3. 通过使用信号量,可以实现多个进程对临界资源的互斥访问,从而解决互斥问题,可以实现进程或语句之间的前趋关系,即实现进程之间的直接制约关系,从而解决同步问题。

七、备注

在老师发的代码中,编译语句由于仅有-lrt而没有-pthread导致报错,在编译过程中添加即可。.

  • 1
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Knight_V_Schumacher

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值