资源描述
操作系统实验报告(Linux版)
网络142 潘豹 142999
实验一 观察Linux进程状态
一、 实验目得
在本实验中学习Linux操作系统得进程状态,并通过编写一些简单代码来观察各种情况下,Linux进程得状态,进一步理解进程得状态及其转换机制。
二、实验环境
硬件环境:计算机一台,局域网环境;
软件环境:Linux Ubuntu操作系统,gcc编译器。
(四)查瞧“不可中断阻塞”状态(D)
创建一个C程序,如uninter_status、c,让其睡眠30s
代码:
#include<unistd、h〉
#include<stdio、h〉
int main()
{
int i=0,j=0,k=0;
for(i=0;i<1000000;i++)
{
for(j=0;j<1000000;j++)
{
k++;
k--;
}
}
}
实验结果:
(二)查瞧“暂停”状态(T)
运行run_status进程,其进入R状态:
代码同上:
(三)查瞧“可中断阻塞”状态(S)
创建一个C程序,如interruptiblie_status、c,让其睡眠30s
编译链接,后台运行该程序(后接&符号),并使用ps命令查瞧运行状态
代码:
#include〈unistd、h>
#include<stdio、h>
int main()
{
sleep(30);
return;
}
实验结果:
(四)查瞧“不可中断阻塞”状态(D)
创建一个C程序,如uninter_status、c,让其睡眠30s
编译链接,后台运行该程序(后接&),并使用ps命令查瞧运行状态
代码:
#include〈unistd、h>
#include〈stdio、h>
int main()
{
if(vfork()==0)
{
sleep(300);
return;
}
}
实验结果:
(五)查瞧“僵尸”进程(Z)
创建一个C程序,如zombie_status、c,在其中创建一个子进程,并让子进程迅速结束,而父进程陷入阻塞
编译链接,后台运行该程序(后接&),并使用ps命令查瞧运行状态(30s内)
代码:
#include<unistd、h>
#incldue<stdio、h>
int main()
{
if(fork())
{
sleep(300);
}
}
实验结果:
实验二 观察Linux进程/线程得异步并发执行
一、实验目得
通过本实验学习如何创建Linux进程及线程,通过实验,观察Linux进程及线程得异步执行。理解进程及线程得区别及特性,进一步理解进程就是资源分配单位,线程就是独立调度单位。
二、实验环境
硬件环境:计算机一台,局域网环境;
软件环境:Linux Ubuntu操作系统,gcc编译器.
三、实验内容与步骤
1、进程异步并发执行
编写一个C语言程序,该程序首先初始化一个count变量为1,然后使用fork函数创建两个子进程,每个子进程对count加1后,显示“I am son, count=x”或“I am daughter, count=x”,父进程对count加1之后,显示“I am father, count=x”,其中x使用count值代替。最后父进程使用waitpid等待两个子进程结束之后退出。
编译连接后,多次运行该程序,观察屏幕上显示结果得顺序性,直到出现不一样得情况为止,并观察每行打印结果中count得值。
代码:
#include<unistd、h>
#include<stdio、h〉
int main()
{
pid_t son_pid,daughter_pid;
int count=1;
son_pid=fork();
if(son_pid==0)
{
count++;
printf(”i am son,count=%d\n",count);
}
else
{
daughter_pid=fork();
if(daughter_pid==0)
{
count++;
printf(”i am daughter,count=%d\n",count);
}
else
{
count++;
printf("i am father,count=%d\n”,count);
waitpid(son_pid,NULL,0);
waitpid(daughter_pid,NULL,0);
}
}
}
2、线程异步并发执行
编写一个C语言程序,该程序首先初始化一个count变量为1,然后使用pthread_create函数创建两个线程,每个线程对count加1后,显示“I am son, count=x”或“I am daughter, count=x",父进程对count加1之后,显示“I am father, count=x”,其中x使用count值代替。最后父进程使用pthread_join等待两个线程结束之后退出。
编译连接后,多次运行该程序,观察屏幕上显示结果得顺序性,直到出现不一样得情况为止,并观察每行打印结果中count得值。
代码:
#include<unistd、h>
#include〈stdio、h〉
#include<pthread、h>
void *daughter(void *num)
{
int* a=(int *)num;
*a+=1;
printf(”i am daughter,count=%d\n",*a);
}
void *son(void *num)
{
int* a=(int *)num;
*a+=1;
printf("i am son,count=%d\n",*a);
}
int main()
{
pthread_t son_tid,daughter_tid;
int count=1;
pthread_create(&son_tid,NULL,son,&count);
pthread_create(&daughter_tid,NULL,daughter,&count);
count++;
printf("i am parent,count:=%d\n”,count);
pthread_join(son_tid,NULL);
pthread_join(daughter_tid,NULL);
return 0;
}
实验结果:
实验三 使用信号量进行互斥与同步
一、 实验目得
本实验介绍在Linux中使用信号量进行进程同步、互斥得方法。读者可以通过实验进一步理解进程间同步与互斥、临界区与临界资源得概念与含义,并学会Linux信号量得基本使用方法。
二、实验环境
硬件环境:计算机一台,局域网环境;
软件环境:Linux Ubuntu操作系统,gcc编译器.
三、实验内容与步骤
三、实验内容与步骤
(一)参考:POSIX以及System V
System V:Unix众多版本中得一支,最初由AT&T定义,目前为第四个版本,其中定义了较为复杂得API。
POSIX:Portable Operating System Interface,IEEE为了统一Unix接口而定义得标准,定义了统一得API接口。Linux即支持System API,又支持POSIX API
(二)实验步骤
step1:通过实例查瞧不使用互斥时得情况 (假设文件命名为no_sem、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;
}
实验结果:
step2:使用信号量来对临界资源进行互斥 (假设文件命名为with_sem、c)
编译链接,同时运行两个进程。
观察X与O得出现规律,并分析原因。
代码:
#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[])
{
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);
sem_close(mutex);
sem_unlink(”mysem”);
exit(0);
}
实验结果:
step3:使用信号量来模拟下象棋红黑轮流走子得情况
编写两个C语言程序black_chess、c以及red_chess、c,分别模拟下象棋过程中红方走子与黑方走子过程。走子规则:红先黑后,红、黑双方轮流走子,到第10步,红方胜,黑方输。
代码:
红色棋
#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);
}
黑色棋 :
#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);
}
实验结果:
实验四 作业调度算法模拟
一、 实验目得
(1)掌握周转时间、等待时间、平均周转时间等概念及其计算方法。
(2)理解五种常用得进程调度算法(FCFS、SJF、HRRF、HPF、RR),区分算法之间得差异性,并用C语言模拟实现各算法。
(3)了解操作系统中高级调度、中级调度与低级调度得区别与联系.
二、实验环境
硬件环境:计算机一台,局域网环境;
软件环境:Linux Ubuntu操作系统,gcc编译器。
三、实验内容与步骤
本实验所选用得调度算法均默认为非抢占式.
实验所用得测试数据如下表所示。
本实验所用得测试数据如下表所示
表 实验测试数据
作业Id
到达时间
执行时间
优先权
1
800
50
0
2
815
30
1
3
830
25
2
4
835
20
2
5
845
15
2
6
700
10
1
7
820
5
0
作业得数据结构:
typedef struct node
{
ﻩint number; // 作业号
int reach_time;// 作业抵达时间
int need_time;// 作业得执行时间
int privilege;// 作业优先权
ﻩfloat excellent;// 响应比
int start_time;// 作业开始时间
int wait_time;// 等待时间
int visited;// 作业就是否被访问过
bool isreached;// 作业就是否已经抵达
}job;
代码:
#include 〈stdio、h>
#include <string、h>
#include <stdlib、h>
#include〈stdbool、h〉
//最大作业数量
const int MAXJOB=50;
//作业得数据结构
typedef struct node
{
int number;//作业号
int reach_time;//作业抵达时间
int need_time;//作业得执行时间
int privilege;//作业优先权
float excellent;//响应比
int start_time;//作业开始时间
int wait_time;//等待时间
int visited;//作业就是否被访问过
bool isreached;//作业就是否抵达
}job;
job jobs[50];//作业序列
int quantity;//作业数量
//初始化作业序列
void initial_jobs()
{
int i;
for(i=0;i〈MAXJOB;i++)
{
jobs[i]、number=0;
jobs[i]、reach_time=0;
jobs[i]、privilege=0;
jobs[i]、excellent=0;
jobs[i]、start_time=0;
jobs[i]、wait_time=0;
jobs[i]、visited=0;
jobs[i]、isreached=false;
}
quantity=0;
}
//重置全部作业信息
void reset_jinfo()
{
int i;
for(i=0;i〈MAXJOB;i++)
{
jobs[i]、start_time=0;
jobs[i]、wait_time=0;
jobs[i]、visited=0;
}
}
//查找当前current_time已到达未执行得最短作业,若无返回-1
int findminjob(job jobs[],int count)
{
int minjob=-1;//=jobs[0]、need_time;
int minloc=-1;
int i;
for(i=0;i<count;i++)
{
if(minloc==-1){
if( jobs[i]、isreached==true && jobs[i]、visited==0){
minjob=jobs[i]、need_time;
minloc=i;
}
}
else if(minjob〉jobs[i]、need_time&&jobs[i]、visited==0&&jobs[i]、isreached==true)
{
minjob=jobs[i]、need_time;
minloc=i;
}
}
return minloc;
}
//查找最早到达作业,若全部到达返回-1、
int findrearlyjob(job jobs[],int count)
{
int rearlyloc=—1;
int rearlyjob=-1;
int i;
for(i=0;i〈count;i++)
{
if(rearlyloc==—1){
if(jobs[i]、visited==0){
rearlyloc=i;
rearlyjob=jobs[i]、reach_time;
}
}
else if(rearlyjob〉jobs[i]、reach_time&&jobs[i]、visited==0)
{
rearlyjob=jobs[i]、reach_time;
rearlyloc=i;
}
}
return rearlyloc;
}
//读取作业数据
void readJobdata()
{
FILE *fp;
char fname[20];
int i;
//输入测试文件文件名
printf(”please input job data \n”);
scanf("%s",fname);
if((fp=fopen(fname,"r"))==NULL)
{
printf(”error, open , please check :\n");
}
else
{
//依次读取作业信息
while(!feof(fp))
{
if(fscanf(fp,"%d %d %d %d”,&jobs[quantity]、number,&jobs[quantity]、reach_time,&jobs[quantity]、need_time,&jobs[quantity]、privilege)==4)
quantity++;
}
//打印作业信息
printf("output the origin job data\n”);
printf(”-—-———-—-—-------—----—--—--——------——--—-——-—---—-—---——--—---—---——\n”);
printf("\tjobID\treachtime\tneedtime\tprivilege\n”);
for(i=0;i〈quantity;i++)
{
printf(”\t%—8d\t%-8d\t%-8d\t%-8d\n",jobs[i]、number,jobs[i]、reach_time,jobs[i]、need_time,jobs[i]、privilege);
}
}
}
//FCFS
void FCFS()
{
int i;
int current_time=0;
int loc;
int total_waitime=0;
int total_roundtime=0;
//获取最近到达得作业
loc=findrearlyjob(jobs,quantity);
//输出作业流
printf(”\n\nFCFS算法作业流\n”);
printf("---—-----—-——---—-——-—--—------———-------——--—-———----—---—-—---—-—-----\n”);
printf("\tjobID\treachtime\tstarttime\twaittime\troundtime\n”);
current_time=jobs[loc]、reach_time;
//每次循环找出最先到达得作业并打印相关信息
for(i=0;i<quantity;i++)
{
if(jobs[loc]、reach_time>current_time)
{
jobs[loc]、start_time=jobs[loc]、reach_time;
current_time=jobs[loc]、reach_time;
}
else
{
jobs[loc]、start_time=current_time;
}
jobs[loc]、wait_time=current_time-jobs[loc]、reach_time;
printf("\t%-8d\t%-8d\t%—8d\t%-8d\t%-8d\n",loc+1,jobs[loc]、reach_time,jobs[loc]、start_time,jobs[loc]、wait_time,
jobs[loc]、wait_time+jobs[loc]、need_time);
jobs[loc]、visited=1;
current_time+=jobs[loc]、need_time;
total_waitime+=jobs[loc]、wait_time;
total_roundtime=total_roundtime+jobs[loc]、wait_time+jobs[loc]、need_time;
//获取剩余作业中最近到达作业
loc=findrearlyjob(jobs,quantity);
}
printf(”总等待时间:%—8d 总周转时间:%-8d\n",total_waitime,total_roundtime);
printf(“平均等待时间: %4、2f 平均周转时间: %4、2f\n”,(float)total_waitime/(quantity),(float)total_roundtime/(quantity));
}
//短作业优先作业调度
void SFJschdulejob(job jobs[],int count)
{
}
int main()
{
initial_jobs();
readJobdata();
FCFS();
reset_jinfo();
SFJschdulejob(jobs,quantity);
system("pause”);
return 0;
}
实验结果:
实验五 Linux内存分配
一、 实验目得
1、了解Linux内存得分配与虚拟内存管理得原理,学习如何使用malloc动态申请内存,了解动态申请与静态申请得区别。
2、深入理解Linux得内存布局:代码段、数据段、BSS段、堆栈段、堆
二、实验环境
硬件环境:计算机一台,局域网环境;
软件环境:Linux Ubuntu操作系统,gcc编译器。
三、实验内容与步骤
第一部分:编程分析Linux中内存动态申请与内存静态申请得区别ﻫ 要求:
1、编写一个Linux C程序,在该程序中使用定义一个全局变量,以及使用malloc申请一段内存(可大于物理内存大小,理论上在32位系统中可以申请小于3G空间,但由于malloc要求申请连续得空间,所以能申请到得空间一般在2G以下)。
2、打印出全局变量得起始地址,以及malloc分配得内存得地址;
3、观察运行结果,并分析说明结果得地址就是否就是物理地址.
代码:
#include〈stdio、h>
#include<stdlib、h〉
int pint[128];
int main()
{
char* pbuf=(char *)malloc(sizeof(char)*1024*1024*1024);
if(pint)
{
printf(”the address of pint is %x\n",pint);
}
if(pbuf)
{
printf("the address of pbuf is %x\n”,pbuf);
}
if(pbuf)
{
free(pbuf);
pbuf=NULL;
}
return 0;
}
实验结果:
第二部分:进一步了解Linux内存得分配与虚拟内存管理得原理、了解Linux得内存布局:代码段、数据段、BSS段、堆栈段、堆.
要求:
1、编写一个Linux C程序,在该程序中定义初始化全局变量、未初始化全局变量、初始化静态变量、未初始化静态变量、局部变量、使用malloc分配得局部变量
2、打印出各种变量得得起始地址
代码:
#include <stdio、h>
#include <stdlib、h〉 //定义两个初始化得全局变量
int data_var0 = 10;
int data_var1 = 10; //定义两个未初始化得全局变量
int bss_var0;
int bss_var1;
int main()
{ //分别定义一个初始化与一个未初始化得静态变量
static int data_var2 = 10;
static int bss_var2;//定义两个局部变量
int stack_var0 = 1;
int stack_var1 = 1;
int stack_var2 = 1;
printf(”———-------——TEXT Segment---——--—-—-\n");
printf(”Address of main: %p\n", main);
printf("—--—---———--DATA Segment—------——--\n”);
printf(”Address of data_var0: %p\n”, &data_var0);
printf(”Address of data_var1: %p\n", &data_var1);
printf("Address of data_var2: %p\n", &data_var2);
printf(”——---—-—--—-BSS Segment—--—-——————\n”);
printf(”Address of bss_var0(BSS Segment): %p\n”, &bss_var0);
printf(”Address of bss_var1(BSS Segment): %p\n”, &bss_var1);
printf("Address of bss_var2(BSS Segment): %p\n”, &bss_var2);
printf("--——-——-———-STACK Segment—----—-—-—-\n”);
printf(”Address of stack_var0: %p\n", &stack_var0);
printf("Address of stack_var1: %p\n”, &stack_var1);
printf(”Address of stack_var2: %p\n”, &stack_var2); //使用malloc分配三个大小为1024B得内存
char* heap_var0 = (char*)malloc(1024);
char* heap_var1 = (char*)malloc(1024);
char* heap_var2 = (char*)malloc(1024); //使用malloc分配三个大小为512MB得内存
char* mmap_var0 = (char*)malloc(1024 * 1024 * 512);
char* mmap_var1 = (char*)malloc(1024 * 1024 * 512);
char* mmap_var2 = (char*)malloc(1024 * 1024 * 512);
printf("----—-—--—-—HEAP Segment—-——-——----\n”);
if(heap_var0){
printf("Address of heap_var0:%p\n”, heap_var0);
free(heap_var0);
heap_var0 = NULL;
}
if(heap_var1){
printf("Address of heap_var1:%p\n”, heap_var1);
free(heap_var1);
heap_var1 = NULL;
}
if(heap_var2){
printf(”Address of heap_var2:%p\n", heap_var2);
free(heap_var2);
heap_var2 = NULL;
}
printf(”—---—----———mmap--—--—----—---—-———\n");
if(mmap_var0){
printf("Address of mmap_var0:%p\n”, mmap_var0);
free(mmap_var0);
mmap_var0 = NULL;
}
if(mmap_var1){
printf("Address of mmap_var1:%p\n", mmap_var1);
free(mmap_var1);
mmap_var1 = NULL;
}
if(mmap_var2){
printf(”Address of mmap_var2:%p\n", mmap_var2);
free(mmap_var2);
mmap_var2 = NULL;
}
return 0;
}
实验结果:
实验六 页面置换模拟程序设计
一、 实验目得
1、通过软件模拟页面置换过程,加深对请求页式存储管理实现原理得理解
2、理解与掌握OPT、FIFO与LRU三种页面置换算法,深入分析三者之间得优缺点.
二、实验环境
硬件环境:计算机一台,局域网环境;
软件环境:Linux Ubuntu操作系统,gcc编译器。
三、实验内容与步骤
代码:
#include<stdio、h>
#include〈stdlib、h>
#include〈string、h〉
#include〈unistd、h〉
#define VM_PAGE 32
#define PM_PAGE 4
#define TOTAL_INSTR 320
#define INSTR_PER_PAGE 10
#define OPT 1
#define FIFO 2
#define LRU 3
typedef struct{
int vmn;
int pmn;
int exist;
int time;
}vpage_item;
vpage_item page_table[VM_PAGE];
vpage_item* ppage_bitmap[PM_PAGE];
typedef struct{
int num;
int vpage;
int offset;
int inflow;
}instr_item;
instr_item instr_array[TOTAL_INSTR];
struct instr_flow{
instr_item*instr;
struct instr_flow*next;
};
struct instr_flow_head{
int num;
struct instr_flow*next;
};
struct instr_flow_head iflow_head;
int pfail_num=0;
int cur_replace_alg=1;
void init_data();
void
展开阅读全文