操作系统课设报告.docx
《操作系统课设报告.docx》由会员分享,可在线阅读,更多相关《操作系统课设报告.docx(26页珍藏版)》请在冰豆网上搜索。

操作系统课设报告
操作系统课程设计报告
题目:
Linux系统管理实践与进程通信实现
姓名
班级:
学号
指导老师
完成日
1.实验目的与要求
1、掌握基本的同步与互斥算法。
2、学习使用LINUX中基本的同步对象,掌握相关函数的使用方法。
3、了解LINUX中多进程的并发执行机制,实现进程的同步与互斥。
4、查阅相关资料。
5、熟悉各种命令、系统调用与实用程序。
按给定功能设计相关程序。
2.实验内容
1.Linux系统的熟悉与常用操作命令的掌握。
2.Linux环境下进程通信的实现。
(实现m个生产者n个消费者的同步互斥问题,缓冲区大小k=5,m=2,n=2)
3.实验设备与环境
在虚拟机LINUX下实现进程间的通信
关于linux相关资料:
Linux是一类Unix计算机操作系统的统称。
Linux操作系统的内核的名字也是“Linux”。
Linux操作系统也是自由软件和开放源代码发展中最著名的例子。
理解Linux文件系统标准
/:
根目录,系统中所有的目录都是从根目录开始
/bin:
存放常用命令
/boot:
引导核心的程序目录
/dev:
外部设备名
/etc:
(etcetera)系统管理所要的配置文件和子目录
/home:
存放用户主目录的地方,一般是/home/用户名。
其他目录有ftp、httpd、samba等
/lib:
(library)系统基本的动态链接库
/lost+found
/opt:
optional(可以选择的)
/proc:
:
虚拟系统,是由系统初起时在内存中产生的
/root:
超级用户默认的主目录;
/sbin:
系统管理员使用的系统管理程序
/tmp:
存放各程序执行时所产生的临时文件
/usr:
占空间最大的目录,用户的很多应用程序和文件几乎全在这个目录中 /var:
存放一些系统记录文件和配置文件
一、LUNIX的登录与退出
1、登录
在DOS环境下用MS提供的telnet程序(也可使用WINDOWS自带的telnet图形界面程序或多功能的S-Term终端程序),可使PC作为终端(terminal)登录(login)UNIX服务器(UNIXServer)。
(1)步骤
login:
(输入username)
password:
(输入密码)
2、退出
在LUNIX系统提示符$下,输入logout、exit或shutdown。
例:
$logout
二、LUNIX命令格式
命令[选项][处理对象]
例:
ls-lamydir
注意:
(1)命令一般是小写字串。
注意大小写有别
(2)选项通常以减号(-)再加上一个或数个字符表示,用来选择一个命令的不同操作
(3)同一行可有数个命令,命令间应以分号隔开
(4)命令后加上&可使该命令后台(background)执行
二.本次实验所用到的指令
1.安装U盘:
ldisk-l
cd/mnt
mkdir"文件名"
mount、dev/sdb1/mnt/"文件名"
cd/mnt/"文件名"
ls
2.编译执行程序:
gccf1.c-of1.out
./f1.out
4.设计过程
1.分析与设计思路
分析:
通过仔细分析可以知道这是一个进程同步问题的模拟,可以把生产产品或消费产品的每一个过程可以转为一个进程的操作,这些进程是互斥的,同时也存在一定的同步关系。
通过编程实践时,实际是随机的调用一个进程的操作,而这些进程的操作相当于程序中的函数调用。
而计算机在执行时每一个时刻只能执行一个操作,这就默认了互斥。
同步的模拟可以类似于函数调用时的前提关系即先决条件。
这样进程同步模拟就完全可以通过进程来实现。
具体的每一个操作的对应的进程的关系:
实现对缓冲区的初始化:
main,要最先执行,且只需要执行一次
生产者1生产产品:
producer1.c
生产者2生产产品:
producer2.c
消费者1消费产品:
consumer1.c
消费者2消费产品:
consumer2.c
在次程序中信号量、共享缓冲区都是系统资源,其总个数是有上限的。
每个资源的id在系统中唯一,并且系统不会主动释放它们,所以要小心使用,及时释放。
在本程序中:
main在执行一次后(成功执行),信号量、共享缓冲区就会分配。
如果再执行它,main会提示资源已经分配,则要释放它们。
设计思路:
设计了4个信号量:
semid_empty:
表示缓冲区中可以再进行产品添加的空间数
semid_full1:
表示生产者1所生产的产品数
semid_full2:
表示生产者2所生产的产品数
semid_mux:
表示其公共的信号量。
设置了4个进程来实现功能:
生产者1生产产品:
producer1.c
生产者2生产产品:
producer2.c
消费者1消费产品:
consumer1.c
消费者2消费产品:
consumer2.c
2.各模块流程图
P、V操作的流程图:
2.生产者与消费者流程图
Y
N
Y
N
5.源代码与实验结果
数据结构
voidset_sembuf_struct(structsembuf*sem,intsemnum,intsemop,intsemflg)
{
/*设置信号量结构*/
sem->sem_num=semnum;
sem->sem_op=semop;
sem->sem_flg=semflg;
}
/*
sem_num:
操作信号在信号集中的编号,第一个信号的编号是0。
sem_op:
如果其值为正数,该值会加到现有的信号内含值中。
通常用于释放所控资源的使用权;如果sem_op的值为负数,而其绝对值又大于信号的现值,操作将会阻塞,直到信号值大于或等于sem_op的绝对值。
通常用于获取资源的使用权;如果sem_op的值为0,则操作将暂时阻塞,直到信号的值变为0。
sem_flg:
信号操作标志
*/
主程序:
main.c
#include
#include
#include
#include
#include
#include
#include
#defineSHMKEY9075/*共享存储区的键*/
#defineSEMKEY_PRODUCER9085
#defineSEMKEY_CONSUMER9086
#defineSEMKEY_MUTEX9087/*信号量数组的键*//*注意:
上面的键在系统中必须唯一*/
#defineBUFF_LEN5/*缓冲区可以存放5个产品*/
#definePRODUCER_LEN32/*每个产品是一个字符串:
<=32字符*/
voidset_sembuf_struct(structsembuf*sem,intsemnum,intsemop,intsemflg)
{
/*设置信号量结构*/
sem->sem_num=semnum;
sem->sem_op=semop;
sem->sem_flg=semflg;
}
/*
sem_num:
操作信号在信号集中的编号,第一个信号的编号是0。
sem_op:
如果其值为正数,该值会加到现有的信号内含值中。
通常用于释放所控资源的使用权;如果sem_op的值为负数,而其绝对值又大于信号的现值,操作将会阻塞,直到信号值大于或等于sem_op的绝对值。
通常用于获取资源的使用权;如果sem_op的值为0,则操作将暂时阻塞,直到信号的值变为0。
sem_flg:
信号操作标志
*/
intmain()
{
char*addr,end;
intshmid;/*共享存储区id*/
intsemid_producer,semid_consumer,semid_mutex;/*信号量集合id*/
structsembufsem_tmp;
/*开辟共享存储区*/
if((shmid=shmget(SHMKEY,BUFF_LEN*PRODUCER_LEN+2,0777|IPC_CREAT|IPC_EXCL))==-1)
{
if(errno==EEXIST)
{
printf("TheBufferHasExisted!
\n");
printf("DoYouWantToDeleteTheBuffer(Y=yes)?
\n=:
");
scanf("%c",&end);
if(end=='y'||end=='Y')
{
/*释放缓冲区*/
shmid=shmget(SHMKEY,BUFF_LEN*PRODUCER_LEN+2,0777);
if(shmctl(shmid,IPC_RMID,0)<0)
perror("shmctl:
");
/*同时释放信号量*/
semid_mutex=semget(SEMKEY_MUTEX,1,0777);
semid_producer=semget(SEMKEY_PRODUCER,1,0777);
semid_consumer=semget(SEMKEY_CONSUMER,1,0777);
semctl(semid_mutex,0,IPC_RMID);
semctl(semid_producer,0,IPC_RMID);
semctl(semid_consumer,0,IPC_RMID);
}
}
else
printf("Failtocreatebuffer!
\n");
return-1;
}
addr=(char*)shmat(shmid,0,0);/*连接缓冲区,将一个共享存储区附接到它的虚拟地址空间去*/
memset(addr,0,BUFF_LEN*PRODUCER_LEN+2);/*将addr所指向的某一块内存中的每个字节的内容全部设置为0的ASCII值,块的大小由BUFF_LEN*PRODUCER_LEN+2指定,返回值为指向addr的指针*/
shmdt(addr);/*离开缓冲区*/
/*创建信号量*/
if((semid_mutex=semget(SEMKEY_MUTEX,1,0777|IPC_CREAT|IPC_EXCL))==-1)
{
if(errno==EEXIST)
printf("TheSEMKEY_MUTEXhasexisted!
\n");
else
printf("FailtocreateSEMKEY_MUTEX!
\n");
return-1;
}
if((semid_producer=semget(SEMKEY_PRODUCER,1,0777|IPC_CREAT|IPC_EXCL))==-1)
{
if(errno==EEXIST)
printf("TheSEMKEY_PRODUCERhasexisted!
\n");
else
printf("FailtocreateSEMKEY_PRODUCER!
\n");
return-1;
}
if((semid_consumer=semget(SEMKEY_CONSUMER,1,0777|IPC_CREAT|IPC_EXCL))==-1)
{
if(errno==EEXIST)
printf("TheSEMKEY_CONSUMERhasexisted!
\n");
else
printf("FailtocreateSEMKEY_CONSUMER!
\n");
return-1;
}
/*给信号量赋初值*/
set_sembuf_struct(&sem_tmp,0,BUFF_LEN,0);/*BUFF_LEN*/
semop(semid_producer,&sem_tmp,1);
set_sembuf_struct(&sem_tmp,0,1,0);/*1*/
semop(semid_mutex,&sem_tmp,1);
set_sembuf_struct(&sem_tmp,0,0,0);/*0*/
semop(semid_consumer,&sem_tmp,1);
return0;
}
producer1.c
/*生产者:
producer.c*/
#include
#include
#include
#include
#include
#include
#include
#defineSHMKEY9075/*共享存储区的键*/
#defineSEMKEY_PRODUCER9085
#defineSEMKEY_CONSUMER9086
#defineSEMKEY_MUTEX9087/*信号量数组的键*//*注意:
上面的键在系统中必须唯一*/
#defineBUFF_LEN5/*缓冲区可以存放5个产品*/
#definePRODUCT_LEN32/*每个产品是一个字符串:
<=32字符*/
/*下面的P,V是对系统调用的简单封装*/
intP(intsemid)
{
structsembufp_buf;
p_buf.sem_num=0;
p_buf.sem_op=-1;
p_buf.sem_flg=0;
if(semop(semid,&p_buf,1)==-1)/*返回在该组操作中最后被操作的信号量在操作完成前的值*/
{
perror("p(semid)falsed");
exit
(1);
}
else
return(0);
}
intV(intsemid)
{
structsembufv_buf;/*structsembuf参见课件ppt*/
v_buf.sem_num=0;
v_buf.sem_op=1;
v_buf.sem_flg=0;
if(semop(semid,&v_buf,1)==-1)
{
perror("v(semid)failed");
exit
(1);
}
else
return(0);
}
main()
{
char*p_buffer;/*共享存储区地址*/
unsignedcharin;/*生产者存放产品的指针:
它的值存放在全局缓冲区第一个字节*/
charproduct[128];/*事实只使用32B,128为了避免屏幕输入超过32*/
intshmid;/*共享存储区id*/
intsemid_producer,semid_consumer,semid_mutex;/*信号量集合id*/
shmid=shmget(SHMKEY,BUFF_LEN*PRODUCT_LEN+2,0777);/*连接共享存储区:
2存放in,out的值*/
/*shmget是建立新的共享区或返回一个已存在的共享描述字*/
p_buffer=(char*)shmat(shmid,0,0);/*取共享存储区地址*/
semid_mutex=semget(SEMKEY_MUTEX,1,0777);/*获取全局信号量id*/
semid_producer=semget(SEMKEY_PRODUCER,1,0777);
semid_consumer=semget(SEMKEY_CONSUMER,1,0777);
/*从屏幕接收产品*/
printf("PleaseProduct(astring,length<=32B):
\n====:
");
gets(product);/*128的意义在此,此函数不检查字符串长度*/
/*进入临界区*/
P(semid_producer);/*对私有信号量作P操作*/
P(semid_mutex);/*对公有信号量作P操作*//*二者顺序不能换*/
in=(unsignedchar)(*p_buffer);
strncpy(p_buffer+2+in*PRODUCT_LEN,product,PRODUCT_LEN);
in=(in+1)%BUFF_LEN;
*p_buffer=(char)in;
shmdt(p_buffer);/*离开缓冲区*/
/*离开临界区*/
V(semid_consumer);
V(semid_mutex);
}
producer2.c
#include
#include
#include
#include
#include
#include
#include
#defineSHMKEY9075/*共享存储区的键*/
#defineSEMKEY_PRODUCER9085
#defineSEMKEY_CONSUMER9086
#defineSEMKEY_MUTEX9087/*信号量数组的键*//*注意:
上面的键在系统中必须唯一*/
#defineBUFF_LEN5/*缓冲区可以存放5个产品*/
#definePRODUCT_LEN32/*每个产品是一个字符串:
<=32字符*/
/*下面的P,V是对系统调用的简单封装*/
intP(intsemid)
{
structsembufp_buf;
p_buf.sem_num=0;
p_buf.sem_op=-1;
p_buf.sem_flg=0;
if(semop(semid,&p_buf,1)==-1)/*返回在该组操作中最后被操作的信号量在操作完成前的值*/
{
perror("p(semid)falsed");
exit
(1);
}
else
return(0);
}
intV(intsemid)
{
structsembufv_buf;/*structsembuf参见课件ppt*/
v_buf.sem_num=0;
v_buf.sem_op=1;
v_buf.sem_flg=0;
if(semop(semid,&v_buf,1)==-1)
{
perror("v(semid)failed");
exit
(1);
}
else
return(0);
}
main()
{
char*p_buffer;/*共享存储区地址*/
unsignedcharin;/*生产者存放产品的指针:
它的值存放在全局缓冲区第一个字节*/
charproduct[128];/*事实只使用32B,128为了避免屏幕输入超过32*/
intshmid;/*共享存储区id*/
intsemid_producer,semid_consumer,semid_mutex;/*信号量集合id*/
shmid=shmget(SHMKEY,BUFF_LEN*PRODUCT_LEN+2,0777);/*连接共享存储区:
2存放in,out的值*/
/*shmget是建立新的共享区或返回一个已存在的共享描述字*/
p_buffer=(char*)shmat(shmid,0,0);/*取共享存储区地址*/
semid_mutex=semget(SEMKEY_MUTEX,1,0777);/*获取全局信号量id*/
semid_producer=semget(SEMKEY_PRODUCER,1,0777);/*获取生产者信号量id*/
semid_consumer=semget(SEMKEY_CONSUMER,1,0777);/*获取消费者信号量id*/
/*从屏幕接收产品*/
printf("PleaseProduct(astring,length<=32B):
\n====:
");
gets(product);/*128的意义在此,此函数不检查字符串长度*/
/*进入临界区*/
P(semid_producer);/*对私有信号量作P操作*/
P(semid_mutex);/*对公有信号量作P操作*//*二者顺序不能换*/
in=(unsignedchar)(*p_buffer);
strncpy(p_buffer+2+in*PRODUCT_LEN,product,PRODUCT_LEN);
in=(in+1)%BUFF_LEN;
*p_buffer=(char)in;
shmdt(p_buffer);/*离开缓冲区*/
/*离开临界区*/
V(semid_consumer);
V(semid_mutex);
}
consumer1.c
#include
#include
#include
#include
#include
#include
#include
#defineSHMKEY9075/*共享存储区的键*/
#defineSEMKEY_PRODUCER9085
#defineSEMKEY_CONSUMER9086
#defineSEMKEY_MUTEX9087/*信号量数组的键*//*注意:
上面的键在系统中必须唯一*/
#defineBUFF_LEN5/*缓冲区可以存放5个产品*/
#defineCONSUMER_LEN32/*每个产品是一个字符串:
<=32字符*/
/*下面的P,V是对系统调用的简单封装*/
intP(intsemid)
{
structsembufp_buf;
p_buf.sem_num=0;
p_buf.sem_op=-1;
p_buf.sem_flg=0;
if(semop(semid,&p_buf,1)==-1)/*返回在该组操作中最后被操作的信号量在操作完成前的值*/
{
perror("p(s