操作系统课程设计任务指导书Word格式文档下载.docx

上传人:b****8 文档编号:22123518 上传时间:2023-02-02 格式:DOCX 页数:59 大小:121.25KB
下载 相关 举报
操作系统课程设计任务指导书Word格式文档下载.docx_第1页
第1页 / 共59页
操作系统课程设计任务指导书Word格式文档下载.docx_第2页
第2页 / 共59页
操作系统课程设计任务指导书Word格式文档下载.docx_第3页
第3页 / 共59页
操作系统课程设计任务指导书Word格式文档下载.docx_第4页
第4页 / 共59页
操作系统课程设计任务指导书Word格式文档下载.docx_第5页
第5页 / 共59页
点击查看更多>>
下载资源
资源描述

操作系统课程设计任务指导书Word格式文档下载.docx

《操作系统课程设计任务指导书Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《操作系统课程设计任务指导书Word格式文档下载.docx(59页珍藏版)》请在冰豆网上搜索。

操作系统课程设计任务指导书Word格式文档下载.docx

最简单的情形是strace执行指定的命令直至命令退出,它可以拦截并记录系统调用信息(包括系统调用名、系统调用参数、系统调用返回值),详细的信息可以参看man手册。

下面演示一个用strace追踪拷贝文件命令cp的例子,执行下面命令:

$stracecpwj1.txtwj5.txt

执行结果的输出包含许多我们不关心的信息,所以我们只列出应该注意的部分:

open("

wj1.txt"

O_RDONLY|O_LARGEFILE)=3

wj5.txt"

O_WRONLY|O_CREAT|O_LARGEFILE,0100644)=4

read(3,"

abcde\n"

4096)=6

write(4,"

6)=6

"

4096)=0

close(4)=0

close(3)=0

我们看到每一项的格式是统一的:

系统调用名系统调用参数返回值

Strace命令有许多选项,其中–c选项特别有用,它能统计系统调用的相关数据,其中包括调用次数,多少次出错返回,系统调用的耗费时间等。

下面是示例产生的结果:

$strace-ccpwj1.txtwj5.txt

%timesecondsusecs/callcallserrorssyscall

------------------------------------------------------------

78.910.00325218118open

21.090.0008698691execve

0.000.000000017read

0.000.00000001write

0.000.000000019close

0.000.000000021access

0.000.00000003brk

0.000.00000006munmap

0.000.00000003mprotect

0.000.000000028mmap2

0.000.00000003stat64

0.000.000000016fstat64

0.000.00000001geteuid32

0.000.00000001set_thread_area

100.000.0041211191total

time命令可以累计一个程序的运行时间。

格式如下:

time[options]command[arguments...]

time在命令command执行结束时在标准错误输出中输出该命令的用时情况,其结果包含下面三项:

1)实际时间(realtime):

从command命令行开始执行到结束经历的时间;

2)用户CPU时间(userCPUtime):

命令执行所占的用户态时间;

3)系统CPU时间(systemCPUtime):

命令执行所占的核心态时间(系统调用时间)。

其中,用户CPU时间和系统CPU时间之和为命令占用CPU执行的时间总和。

一般说来,实际时间要大于CPU时间,因为comand可能和其他进程交替执行。

下面是一个具体例子,测试ls命令递归列出当前目录内容所用时间。

$timels-R

执行结果如下:

.......(ls命令结果略)

real0m2.612s

user0m0.080s

sys0m2.524s

值得提醒的是,依赖于操作系统的计时机制,time命令本身不一定很精确;

此外,command的执行时间依赖于环境,所以同一命令执行多次结果也可能不同,一个比较合理的做法是一个命令执行多次然后取平均值。

mmap介绍

mmap指memory-mapped(存储映射),其将文件内容映射到进程地址空间,相比传统方法而言,往往能够减少系统调用和内容拷贝次数,从而提高性能。

其函数原型如下:

void*mmap(void*addr,size_tlen,intprot,intflags,intfd,off_toffset);

函数的返回值为最后文件映射到进程空间的地址,进程可直接操作起始地址为该值的有效地址。

参数addr指定文件应被映射到进程空间的起始地址,一般被指定一个空指针,此时选择起始地址的任务留给内核来完成(参见flags的说明)。

参数fd为即将映射到进程空间的文件描述字,一般由open()返回,同时,fd可以指定为-1,此时须指定flags参数中的MAP_ANON,表明进行的是匿名映射。

len是映射到调用进程地址空间的字节数,它从被映射文件开头offset个字节开始算起。

prot参数指定共享内存的访问权限。

可取如下几个值的或:

PROT_READ(可读),PROT_WRITE(可写),PROT_EXEC(可执行),PROT_NONE(不可访问)。

flags由以下几个常值指定:

MAP_SHARED,MAP_PRIVATE,MAP_FIXED,其中,MAP_SHARED,MAP_PRIVATE必选其一,而MAP_FIXED则不推荐使用。

offset参数一般设为0,表示从文件头开始映射。

下面给出一个使用mmap输出文件内容的例子:

#include<

stdio.h>

stdlib.h>

sys/mman.h>

sys/types.h>

sys/stat.h>

fcntl.h>

intmain(intargc,char*argv[])

{

intsrc;

char*sm;

structstatstatbuf;

size_tfz;

if(argc!

=2)

{

fprintf(stderr,"

Usage:

%s<

sourcefile>

\n"

argv[0]);

exit(EXIT_FAILURE);

}

if((src=open(argv[1],O_RDONLY))<

0)

perror("

opensource"

);

if(fstat(src,&

statbuf)<

0)

fstatsource"

fz=statbuf.st_size;

sm=mmap(0,fz,PROT_READ,

MAP_PRIVATE|MAP_NORESERVE,src,0);

if(MAP_FAILED==sm)

perror("

mmapsource"

while(fz){

putchar(*sm++);

fz--;

return(EXIT_SUCCESS);

}

任务二实现一个简单的shell

本任务主要目的在于学会如何在Unix系统下创建进程和管理进程,了解shell工作的基本原理。

实现一个简单的shell(命令行解释器),类似于sh,bash,csh等。

你的shell必须支持以下内部命令

cd<

目录>

更改当前的工作目录到另一个<

如果<

未指定,输出当前工作目录。

不存在,应当有适当的错误信息提示。

这个命令应该也能改变PWD的环境变量。

environ列出所有环境变量字符串的设置(类似于Unix系统下的env命令)。

echo<

内容>

显示echo后的内容且换行

help简短概要的输出你的shell的使用方法和基本功能。

jobs输出shell当前的一系列子进程,必须提供子进程的命名和PID号。

quit,exit,bye退出shell。

所有的内部命令应当优先于在$PATH中同名的程序。

任何非内部命令必须请求shell创建一个新进程,且该子进程执行指定的程序。

这个新进程必须继承shell的环境变量和指定的命令行参数。

Shell应当具有以下特征:

BatchProcessing如果shell启动带有一个文件名作为参数,打开该文件并执行文件里所有命令。

待所有进程全部结束退出shell。

该功能类似于shell的交互模式。

Debugging提供-v选项,shell启动时打开此选项将在运行过程中输出若干调试信息。

在该种模式下,shell应该显示所有被创建了的进程的PID号,通报已结束的子进程和传递给子进程的参数等。

Prompt(命令行提示符)解释器应该打印$PS2(而不是$PS1)作为提示符。

Backgroundprocessing如果命令以符号&

终止,在后台并发执行该程序。

shell立即等待下一命令行的输入,而不等待该程序的结束。

Redirect(重定向)该功能选做

Pipe(管道)该功能选做

你可假定所有的命令和参数由空格或tab符分开。

相关知识介绍

shell的主体就是反复下面的循环过程

while

(1){

接收用户输入的命令行;

解析命令行;

if(用户命令为内部命令)

直接处理;

elseif(用户命令为外部命令)

创建子进程执行命令;

else

提示错误的命令;

创建子进程要使用fork()函数,执行新的命令要使用exec()系列函数,通常shell是等待子进程结束后再接受用户新的输入,这可以使用waitpid()函数。

下面是一个完整的示例:

unistd.h>

sys/wait.h>

intmain(void)

pid_tpid;

if((pid=fork())<

0){

printf("

forkerror\n"

);

exit(EXIT_FAILURE);

}elseif(pid==0){/*childprocess*/

if(execl("

/bin/ls"

"

ls"

-l"

(char*)0)<

execlerror\n"

waitpid(pid,0,0);

/*waitforchildprocess*/

exit(0);

Fork()原型如下:

pid_tfork(void);

fork建立一个子进程,父进程继续运行,子进程在同样的位置执行同样的程序。

对于父进程,fork()返回子进程的pid,对于子进程,fork()返回0。

出错时返回-1。

Exec系列有6个函数,原型如下:

externchar**environ;

intexecl(constchar*path,constchar*arg,...);

intexeclp(constchar*file,constchar*arg,...);

intexecle(constchar*path,constchar*arg,...,char*constenvp[]);

intexecv(constchar*path,char*constargv[]);

intexecve(constchar*filename,char*constargv[],char*constenvp[]);

intexecvp(constchar*file,char*constargv[]);

exec系列函数用新的进程映象置换当前的进程映象.这些函数的第一个参数是待执行程序的路径名(文件名).这些函数调用成功后不会返回,其进程的正文(text),数据(data),bss和堆栈(stack)段被待执行程序程序覆盖。

但是进程的PID和所有打开的文件描述符没有改变,同时悬挂信号被清除,信号重置为缺省行为.

在函数execl,execlp,和execle中,constchar*arg以及省略号代表的参数可被视为arg0,arg1,...,argn.他们合起来描述了指向NULL结尾的字符串的指针列表,即执行程序的参数列表.作为约定,第一个arg参数应该指向执行程序名自身,参数列表必须用NULL指针结束.

execv和execvp函数提供指向NULL结尾的字符串的指针数组作为新程序的参数列表.作为约定,指针数组中第一个元素应该指向执行程序名自身.指针数组必须用NULL指针结束。

execle函数同时说明了执行进程的环境(environment),他在NULL指针后面要求一个附加参数,NULL指针用于结束参数列表,或者说,argv数组.这个附加参数是指向NULL结尾的字符串的指针数组,他必须用NULL指针结束。

其他函数从当前进程的environ外部变量中获取新进程的环境.

execlp和execvp可根据path搜索合适的程序运行,其他则需要给出程序全路径。

Execve()类似execv(),但是加上了环境的处理。

Wait(),waitpid()

可用来等待子进程结束。

函数原型:

pid_twait(int*stat_loc);

pid_twaitpid(pid_tpid,int*stat_loc,intoptions);

当进程调wait,它将进入睡眠状直到有一个子进程结束。

wait函数返回子进程的进程id,stat_loc中返回子进程的退出状态。

waitpid的第一个参数pid的意义:

pid>

0:

等待进程id为pid的子进程。

pid==0:

等待与自己同组的任意子进程。

pid==-1:

等待任意一个子进程

pid<

-1:

等待进程组号为-pid的任意子进程。

因此,wait(&

stat)等价于waitpid(-1,&

stat,0)

waitpid第三个参数option可以是0,WNOHANG,WUNTRACED或这几者的组合。

任务三进程/线程同步

本任务主要目的练习UNIX/LINUX同步编程,熟悉基本的线程相关API。

编程实现下图的效果,要求分别使用进程和线程

(1)进程+SYSV信号量

(2)线程实现+Posix同步操作API

无论进程形式还是线程形式,进程/线程pi的主体反复输出下面语句:

Iamprocess(orthread)pi

执行次数取必须保证进程并发情况的发生(比如p3和p4的交迭运行),大家自行调整。

必须保证parbegin(p1(),p2(),……,p6())并发形式的充分发生,一个典型的输出系列如下:

Iamthread1

.....

Iamthread3

Iamthread2

Iamthread4

Iamthread3

Iamthread5

Iamthread4

Iamthread6

.....

SYSV信号量API介绍

SystemV信号量最早为SystemV操作系统实现,故而得名。

Linux也支持SystemV信号量,SystemV信号量的函数主要有下面几个.

sys/ipc.h>

sys/sem.h>

intsemget(key_tkey,intnsems,intsemflg);

semget调用成功时返回信号量组ID(可能已经存在或通过创建新的),否则返回值为-1。

key是一个关键字,可以是用ftok()函数创建的也可以是IPC_PRIVATE表明由系统选用一个关键字。

nsems是这个信号量组中信号量的数量。

semflg是创建的权限标志,本设计中要用到IPC_CREAT。

intsemctl(intsemid,intsemnum,intcmd,.../*unionsemunarg*/);

semctl对信号量进行一系列的控制。

semid是要操作的信号量组ID,semnum是信号量组的下标,指明待操作的具体信号量,cmd是操作的命令。

经常用的两个值是:

SETVAL(设置信号量的值)和IPC_RMID(删除信号量)。

arg是一个根据cmd的设置参数。

intsemop(intsemid,structsembuf*spos,intnspos);

structsembuf{

shortsem_num;

/*在信号量组中的下标(0,1,...,nsems-1),表明对哪一个信号量操作*/

shortsem_op;

/*进行什么操作*/

shortsem_flg;

/*操作的标志,有IPC_NOWAIT,SEM_UNDO等*/

};

semop是对信号组进行操作的函数。

semid是信号量组ID,spos是一个操作数组,nspos表明操作数组的大小。

如果sem_op大于0,那么操作将sem_op加入到信号量的值中。

如果为0,当信号量的值是0的时候,函数返回,否则阻塞直到信号量的值为0。

如果小于0,函数判断信号量的值加上这个负值。

如果结果为0唤醒等待信号量为0的进程,如果小与0函数阻塞。

如果大于0,那么从信号量里面减去这个值并返回。

如果IPC_NOWAIT被设置,上面操作不满足时立即返回。

注意,semop是原子操作,也即操作数组不可能部分完成时semop就返回,要么彻底失败,要么全部完成。

函数操作成功时返回0。

本任务中可以先使用semget()创建信号量,然后使用semctl()设置信号量初值,然后通过semop()对信号量操作。

Posix线程编程介绍

下面只是一个简单的介绍,更详细的信息请查阅相关资料。

POSIX通过pthread_create()函数创建线程,API定义如下:

intpthread_create(pthread_t*thread,pthread_attr_t*attr,

void*(*start_routine)(void*),void*arg);

thread:

当pthread_create创建成功,*thread放入新创建的线程ID。

attr:

可用来定义线程的某些属性,本任务缺省的线程属性是适用的,只需将该参数设为NULL。

第三个参数start_routine是新线程启动时调用的函数名。

当start_routine返回时,新线程将终止。

第四个参数arg用作start_routine的参数

/*filethread1.c*/

pthread.h>

void*thread_function(void*arg){

inti;

for(i=0;

i<

20;

i++){

Threadisrunning!

\n"

sleep

(1);

returnNULL;

intmain(void){

pthread_tmythread;

if(pthread_create(&

mythread,NULL,thread_function,NULL)){

errorcreatingthread."

abort();

if(pthread_join(mythread,NULL)){

errorjoiningthread."

注意main()主体是主线程,当pthread_create()创建线程后,系统就有两个线程,线程并发执行,绝对不能假定两者的相对执行次序。

为了

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 解决方案 > 学习计划

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1