1、操作系统实验说明书操作系统课程组2008-10 修订实验内容:LINUX 系统通过全世界众多软件高手,特别是 Linus 本人的不懈努力,使 Linux 能支持多种硬件平台(X86、Alpha、PowerPC、SPARC、ARM) ,至今已发展成为主流操作系统的一员。随着 Linux 的优良性能不断显现,IBM、Intel、Sun 等不少商业科技巨头纷纷涉足 Linux. 今天,操作系统正向着大型和微型两个不同的方向发展着。大型系统的典型是分布式操作系统和集群操作系统,而微型系统的典型则是嵌入式操作系统。应该说 Linux 为操作系统研究者提供了新理论、新方法、新技术的实践和验证平台,同时反过
2、来促进了操作系统的不断发展,因而可以说 Linux 特别适合于操作系统课程的教学,在 Linux 上的实验主要分成 3 个部分1 LINUX 基本命令2 LINUX 下 VI 操作3 VI 下系统调用及进程通信等程序设计实验(12 学时) 一、 实验目的 通过实验,使学生加深对操作系统课程部分理论知识的理解,并了解当今流行的 LINUX 操作系统的操作命令,以及其下有关进程、线程的程序设计。 二、 实验内容和学时安排 实验内容 课时实验一 LINUX 基本命令及 vi 下编程环境 3实验二 LINUX 下 VI 基本操作 3实验三 进程/线程通信与程序设计 6三、 实验内容 实验一 LINUX
3、 基本命令及编程环境 1. 实验的基本目的 通过上机操作,了解 linux 操作系统的特点,及常用命令。 linux 是一个分时、多用户、多任务的操作系统。它具有精简的核心。linux 提供两种用户界面:一种是交互命令,即用户在终端上通过使用命令交互调用核外程序;另一种是系统调用,即用户编写程序时通过使用 C 语言的函数调用来调用系统核心功能。本实验熟悉 Linux 操作环境,及 Linux 各类命令基本操作的使用方法。 2 LINUX 基本命令命令 解释 用法 举例ls显示某一个目录下的内容(文件和目录)用法: ls 或者 ls 目录ls 后为空时表示显示当面目录下的内容。可以在 ls 后面
4、加上所要查看的目录路径名称lsls /ls /home/ls /etc/sysconfls -l 详细显示 用法:ls l 或者 ls l 目录注:l 为字母,不是数字 1。 ls -lls l /homels -a 显示所有的文件用法:ls a 或者 ls a 目录以.开始的文件为隐藏文件,此时也会显示,其他情况下不显示ls als la /etc/cp 复制文件 用法:cp 原文件 目标文件注:文件可以加上路径名 cp/home/lion/test1 /home/lion/test/test2cp -r 复制整个目录 用法:cp r 原目录 目标目录注:目录下的所有文件都会复制 cp/ho
5、me/lion/mjli /home/lion/test/mjli2mv 移动文件或者目录和 cp 用法类似,但是移动后,原文件或者目录不存在。注:移动目录时不用-r 参数mv/home/lion/test1 /home/lion/test2mv/home/lion/mjli /home/lion/mjli2touch 创建文件 用法:touch 文件名 touch /home/lion/test1mkdir 创建目录 用法:mkdir 目录名 touch /home/lion/mjlirm 删除文件 用法:rm 文件名 rm /home/lion/test1rm -r 删除目录 用法:rm
6、r 目录名 rm r /home/lion/mjli2rmdir 删除空的目录用法:rmdir 目录名注:此目录必须为空,否则无法删除rmdir /home/lion/mjli2cd 改变目录路径 用法:cd 目录名 cd /etccd /home/lioncd 到上一层目录中 用法:cd cd cd / 到根目录下 用法:cd / cd /pwd 显示当前的目录路径 用法:pwd pwdcat 查看文件内容用法:cat 文件名 cat /home/lion/test1可以没有文件名,表示接收键盘,以 ctrl+C结束more 查看较长内容的文件用法:more 文件名注:在显示中,按空格键滚动
7、一页,按回车键滚动一行,按 q 键退出more /home/lion/test2less 查看较长内容的文件 与 more 用法类似。Pgup、Pgdown,y 向上滚动一行 less /home/lion/test2ps aux 查看系统的进程 注意:参数 aux 最好一起使用 ps auxw 显示在线用户信息 用法:w注:比命令 who 的信息详细 wwhotop显示系统任务信息,包括 cpu、内存等用法:top topmesg 是否接受其他人的 write 信息 用法:mesg y 或者 mesg n注:y 为接受,n 为不接受。 mesg ymesg nwrite 传送信息给其他用户用
8、法: write 用户 或者 write 用户 TTY。注:TTY 用于有区别多个同样的用户,可由 w 命令来获取。write lionwrite lion pts/2Ctrl +C 退出passwd 修改密码用法:passwd注:超级用户可修改其他用户密码,此时为 passwd 用户passwddu显示目录下的各个文件的占用磁盘情况(包括子目录下文件)用法:du 目录名注:无目录名时为当前目录dudu /home/liondu -s 显示目录下的所有文件的大小 用法:du s 目录名注:无目录名时为当前目录 du sdu s /home/liondate 显示系统日期和时间 用法:date
9、dateuptime 显示系统运行时间 用法:uptime uptimeclear 清除当前屏幕 用法:clear clearwc统计文件,给出文件的行数、字数、字符数用法:wc 文件名 wc /home/lion/test1grep 过滤文本和其他命令连用,如ls |grep sring 为只显示具有string 的行cat 文件名|grep string 为只显示文件中具有 string 的行ls l|grep stringcat /home/lion |grep heheps aux|grep test1grep n过滤文本,把所找到的行在行前加上行号列出用户与 grep 类似,加上参数
10、即可 ls l|grep n stringps aux|grep -n test1grep v过滤文本,把不包含给定string 的行列出用户与 grep 类似,加上参数即可 ls l|grep v stringps aux|grep v test1grep string 搜索文本用法:grep string r 目录名在给定目录下搜索所有文件中含grep string r /grep hehe r -r 有 string 的行注:也可加-n v 参数。/home/liondf 查看系统硬盘信息 用法:df dffree 查看系统内存信息 用法:free freeping 查看与对方机器是否连
11、接 用法:ping IP 地址或者域名 ping ping 202.38.64.1echo 回应输入内容 用法:echo string注:结果将显示 string echo helloecho hehewhoami 显示当前正在进行操作的用户名 用法:whoami whoamiexit 退出登录系统 用法:exit exitctrl+C 中止程序执行 用法:ctrl+C ctrl+Cctrl+D 退出系统 用法:ctrl+D ctrl+Dchmod 详见下面说明chmod 为改变文件权限。在 linux 中,一个文件上有可读(r)可写(w)可执行(x)三种模式,分别针对该文件的拥有者(onwe
12、r)、同组者(group),和其他人(other) 。一个文件如果改成可执行模式则系统就将其视为一个可执行文件,而一个目录的可执行模式代表使用者有进入该目录之权利。chmod 就是用来变更一些文件的模式,其使用方式如下:chmod -R mode 文件名-R 将所有子目录及文件改为你所要改成的模式。其中模式即可以用数字表示也可以用字母表示,分别表示如下:1)数字按照拥有者、同组者、其他人的顺序,给出一个三位的数字,r 为 4,w 为 2,x为 1,例如 765 第一个数字 7 表示拥有者具有 r+w+x 的权限(7=4+2+1) ,第二个数字 6 表示同组者具有 r+w 权限(6=4+2) ,
13、第三个数字 5 表示其他人具有 r+x 权限(5=r+x) 。用法: chmod 765 文件名可将其中的数字更改为所需要的权限即可。2)字母用法:chmod ugo+/-rwx 文件名例如:chmod u+r /home/lion/test1chmod ug+rx /home/lion/mjli/其中可以同时出现,其意义分别如下:+或- r w xu u+r, u-r 表示拥有者拥有或者取消可读权限同理 同理g g+r, g-r 表示同组者拥有或者取消可读权限同理 同理o o+r, o-r 表示其他人拥有或者取消可读权限同理 同理*其他特别命令:解释 输出由屏幕重定向到文件中,文件原来内容被
14、清空用法:命令 文件名注:命令可以为以上的命令,文件名可有目录路径ls l /home/lion/result 输出由屏幕重定向到文件的末尾中,文件原来内容被保留类似 ,只是保留了原文件的内容。ls l /home/lion / result /#include #include main ()pid_t(改为 int) pid; /* pid_t 是 short 类型 */pid=fork();if (pid #include main () char ch; pid_t(改为 int) pid;pid=fork();if (pid int pipe(int p2);如果正常, 返回 0,
15、有错则返回 -1.pipe() 把 p 与两个文件描述符紧密联系起来:p0 用于从管道读p1用于向管道写1)例子 2-1. 利用 pipe() 和 fork()#include #include #include p0p1管道p进程 1进程 2#include #define MSGSIZE 16 /* 正文 + 空 */char *msg1=“hello, world #1”;char *msg2=“hello, world #2”;char *msg3=“hello, world #3”;int main() char inbufMSGSIZE;int p2, i, pid;if (pip
16、e(p) 0) /* 父进程 */ close(p0); /* 关闭读端(连接) */write(p1, msg1, MSGSIZE);write(p1, msg2, MSGSIZE);write(p1, msg3, MSGSIZE);wait(int *)0);什么意思? if (pid = 0) /* 子进程 */ close(p1); /* 关闭写端 */for (i=0; i #includemain()int p1,p2,i;int *fp;fp = fopen(“family.txt“,“w+“); /*打开文件 family.txt*/if(fp=NULL)printf(“Fai
17、l to create file“);exit(-1);while(p1=fork()=-1); /*创建子进程 p1*/if(p1=0)lockf(*fp,1,0); /*加锁*/for(i=0;i #include #include #include int wait_flag; void stop(); main( ) int pid1, pid2; signal(3,stop); /* 或者 signal(14,stop)*/ while(pid1 = fork( ) = -1); if(pid1 0) while(pid2 = fork( ) = -1); if(pid2 0) wa
18、it_flag = 1; sleep(5); kill(pid1,16); kill(pid2,17); wait(0); wait(0); printf(“n Parent process is killed !n”); exit(0); else wait_flag = 1; signal(17,stop); printf(“n Child process 2 is killed by parent !n”); exit(0); else wait_flag = 1; signal(16,stop); printf(“n Child process 1 is killed by paren
19、t !n”); exit(0); void stop( ) wait_flag = 0; 4)闹钟:用 fork( )创建两个子进程,子进程在等待 5 秒后用系统调用 kill()向父进程发送 SIGALARM 信号,父进程用系统调用 signal( )捕捉 SIGLARM 信号。#include #include #include #DEFINE static int alarm_fired = 0; /*闹钟未设置 */*模拟闹钟 */void ding(int sig)alarm_fired = 1; /*设置闹钟 */int main()int pid;printf(“alarm ap
20、plication startingn“);if(pid = fork( ) = 0) /*子进程 5 秒后发送信号 SIGALRM 给父进程*/sleep(5);kill(getppid(), SIGALRM);exit(0);printf(“waiting for alarm to go offn“);/*父进程安排好捕捉到 SIGALRM 信号后执行 ding 函数*/(void) signal(SIGALRM, ding); pause(); /*挂起父进程,直到有一个信号出现*/if (alarm_fired)printf(“Ding!n“);printf(“donen“);exit
21、(0);5线程的创建与应用 1)“hello world“多线程程序#include #include main()pthread_t p1 , p2;void *p_msg(char *);pthread_create(pthread_create(pthread_join(t1, NULL);pthread_join(t2, NULL);void *p_msg(char *m)char *cp =(char *) m;int i;for(i = 0 ; i #include #include int total_words;pthread_mutex_t counter_lock =PTH
22、READ_MUTEX_INITIALIZER; /*互斥锁*/main(int ac , char *av)pthread_t t1, t2;void *count_words(void *);if(ac!=3)printf(“usage: % s file1 file2n“,av0);exit(1);total_words = 0;pthread_create(pthread_create(pthread_join(t1, NULL);pthread_join(t2, NULL);printf(“% 5d: total wordsn“, total_words);void *count_wo
23、rds(void *f)char * filename = (char * ) f;FILE *fp;int c,prevc = 0;if(fp = fopen(filename, “r“)!=NULL)while(c = getc(fp)!= EOF)if(!isalnum(c) total_words+;pthread_mutex_unlock(prevc =c;fclose(fp); elseperror(filename);return NULL;6编写一个简单的 shell 命令过程/程序(批处理文件)利用 vi 编写命令过程文件 shell1.shvi shell1.sh /*进入
24、编写命令过程*/vi proc1.cgcc -o test1.out proc1.c* 练习编写一个命令过程 commsh:vi commsh内容可以为:clearecho is studying the linux systemcat temp.txtls l | moreecho is waiting for inputting a character ./fork2.out退出 commsh 的编辑后,执行./commsh7银行家算法编程 1).实验的基本目的: 熟悉银行家算法,加深死锁有关概念的理解。2)实验的基本内容: 假定: 系统中有五个进程:P0、P1、P2、P3、P4 4 类资
25、源A,B,C,D 每一种资源的数量分别为:3、14,12、12* 问题: 请找出该表中 T0 时刻以后存在的安全序列(是否有多种?) 在 T0 时刻的资源分配情况如图资源情况进程MaxA B C DAllocationA B C DNeedA B C DAvailableA B C DP- 0 0 1 2 0 0 1 2 0 0 0 0 1 5 2 0P1 1 7 5 0 1 0 0 0 0 7 5 0P2 2 3 5 6 1 3 5 4 1 0 0 2P3 0 6 5 2 0 6 3 2 0 9 2 0P4 0 6 5 6 0 0 1 4 0 6 4 2 一个简单银行家算法示例:请进行修改#
26、include void main()int r_max53=7,5,3,3,2,2,9,0,2,2,2,2,4,3,3;int alloc53=0,1,0,2,0,0,3,0,2,2,1,1,0,0,2;int i,j,k,count=0;int need53=0,0,0,0,0,0,0,0,0,0,0,0,0,0,0;int finish5=-1,-1,-1,-1,-1;int work3=3,3,2;printf(“available:n A B Cn 3 3 2nn“);for(i=0;i“,k);if(count=5)printf(“nit is safe!n“);elseprint
27、f(“nit is dangern“);四、附录附录 1主要系统调用及简要功能说明下面列出了大部分常见的 Linux 系统调用,并附有简要中文说明。以下是 Linux 系统调用的一个列表,包含了大部分常用系统调用和由系统调用派生出的的函数(删去了几个仅供内核使用,不允许用户调用的系统调用)。其中有一些函数的作用完全相同,只是参数不同。(可能很多熟悉 C+马上就能联想起函数重载,但是别忘了 Linux 核心是用 C 语言写的,所以只能取成不同的函数名)。还有一些函数已经过时,被新的更好的函数所代替了(gcc 在链接这些函数时会发出警告),但因为兼容的原因还保留着。一、进程控制:Fork 创建一个
28、新进程clone 按指定条件创建子进程execve 运行可执行文件Exit 中止进程_exit 立即中止当前进程sleep(n) 睡眠(等待/阻塞),n 为秒的单位getpid 获取进程标识号getppid 获取父进程标识号pause 挂起进程,等待信号Wait(参数) 等待子进程终止waitpid 等待指定子进程终止二、文件系统控制1、文件读写操作fcntl 文件控制open 打开文件creat 创建新文件close 关闭文件描述字read 读文件write 写文件readv 从文件读入数据到缓冲数组中writev 将缓冲数组里的数据写入文件2、文件系统操作chdir 改变当前工作目录chm
29、od 改变文件方式fchmod 参见 chmodchown 改变文件的属主或用户组mkdir 创建目录mknod 创建索引节点rmdir 删除目录rename 文件改名link 创建链接symlink 创建符号链接unlink 删除链接三、进程间通信1、信号signal 参见 signalKill 向进程或进程组发信号2、管道Pipe 创建管道附录 2。信号软中断信号(signal,又简称为信号)用来通知进程发生了异步事件。进程之间可以互相通过系统调用 kill 发送软中断信号。内核也可以因为内部事件而给进程发送信号,通知进程发生了某个事件。注意,信号只是用来通知某进程发生了什么事件,并不给该
30、进程传递任何数据。收到信号的进程对各种信号有不同的处理方法。处理方法可以分为三类:1是类似中断的处理程序,对于需要处理的信号,进程可以指定处理函数,由该函数来处理。2 忽略某个信号,对该信号不做任何处理,就象未发生过一样。3 对该信号的处理保留系统的默认值,这种缺省操作, 对大部分的信号的缺省操作是使得进程终止。进程通过系统调用 signal 来指定进程对某个信号的处理行为。在进程表的表项中有一个软中断信号域,该域中每一位对应一个信号,当有信号发送给进程时,对应位置位。由此可以看出,进程对不同的信号可以同时保留,但对于同一个信号,进程并不知道在处理之前来过多少个。发出信号的原因很多,这里按发出
31、信号的原因简单分类,以了解各种信号:1. 与进程终止相关的信号。当进程退出,或者子进程终止时,发出这类信号。 2. 与进程例外事件相关的信号。如进程越界,或企图写一个只读的内存区域(如程序正文区) ,或执行一个特权指令及其他各种硬件错误。 3. 与在系统调用期间遇到不可恢复条件相关的信号。如执行系统调用 exec 时,原有资源已经释放,而目前系统资源又已经耗尽。 4. 与执行系统调用时遇到非预测错误条件相关的信号。如执行一个并不存在的系统调用。 5. 在用户态下的进程发出的信号。如进程调用系统调用 kill 向其他进程发送信号。 6. 与终端交互相关的信号。如用户关闭一个终端,或按下 brea
32、k 键等情况。 7. 跟踪进程执行的信号。Linux 支持的信号列表如下。很多信号是与机器的体系结构相关的。首先列出的是 POSIX.1 中列出的信号:信号 值 处理动作 发出信号的原因SIGHUP 1 A 终端挂起或者控制进程终止SIGINT 2 A 键盘中断(如 break 键被按下)SIGQUIT 3 C 键盘的退出键被按下SIGILL 4 C 非法指令SIGABRT 6 C 由 abort(3)发出的退出指令SIGFPE 8 C 浮点异常SIGKILL 9 AEF Kill 信号SIGSEGV 11 C 无效的内存引用SIGPIPE 13 A 管道破裂: 写一个没有读端口的管道SIGA
33、LRM 14 A 由 alarm(2)发出的信号SIGTERM 15 A 终止信号SIGUSR1 30,10,16 A 用户自定义信号 1SIGUSR2 31,12,17 A 用户自定义信号 2SIGCHLD 20,17,18 B 子进程结束信号SIGCONT 19,18,25 进程继续(曾被停止的进程)SIGSTOP 17,19,23 DEF 终止进程SIGTSTP 18,20,24 D 控制终端(tty)上按下停止键SIGTTIN 21,21,26 D 后台进程企图从控制终端读SIGTTOU 22,22,27 D 后台进程企图从控制终端写处理动作一项中的字母含义如下: A 缺省的动作是终止
34、进程 B 缺省的动作是忽略此信号 C 缺省的动作是终止进程并进行内核映像转储(dump core) D 缺省的动作是停止进程 E 信号不能被捕获 F 信号不能被忽略附录 3有关线程(pthread)函数/调用的简要说明1.创建线程int pthread_create(pthread_t *restrict ptid,const pthread_attr_t *restrict attr,void *(*start_routine)(void*), void *restrict arg);ptid 是一个 pthread_t *类型的指针,pthread_t 是类似 pid_t 的数据结构,表示
35、线程 ID;attr 指明线程创建属性,如果为 NULL 就使用系统默认属性;start_routine 是线程的主函数,它的参数是 void *类型的指针,返回值也是 void *类型的指针;arg 是线程创建者传递给新建线程的参数,也就是 start_routine 的参数。注意,线程创建者和新建线程之间没有 fork()调用那样的父子关系,它们是对等关系。调用 pthread_create()创建线程后,线程创建者和新建线程哪个先运行是不确定的,特别是在多处理机器上。2.终止线程void pthread_exit(void *value_ptr);线程调用 pthread_exit()结
36、束自己,参数 value_ptr 被调用pthread_join 的线程使用。3.pthread_self()得到线程 ID4.pthread_equal()比较线程 ID,线程 ID 的大小没有意义。5.取消线程int pthread_cancel(pthread_t thread);向线程 thread 发送取消请求,默认情况下线程 thread 自己调用pthread_exit(PTHREAD_CANCELED),可以在创建线程时通过 attr 改变默认行为。pthread_cancel 并不阻塞调用者,总是立即返回。6.连接线程-阻塞int pthread_join(pthread_t
37、 thread, void *value_ptr);等待一个线程 thread 结束,并设置*value_ptr 为 thread 的返回值。pthread_join 阻塞调用者,一直到线程 thread 结束为止。线程终止有一下几种方法:1)从主函数返回,2)自己调用 pthread_exit(),3)其他线程调用 pthread_cancel(),4)线程所属的进程中任何线程调用 exit()导致所有线程结束。第一个参数为被等待的线程标识符,第二个参数为一个用户定义的指针,他能够用来存储被等待线程的返回值。这个函数是个线程阻塞的函数,调用他的函数将一直等待到被等待的线程结束为止,当函数返回时,被等待线程的资源被收回。最后要说明的是,一个线程不能被多个线程等待,否则第一个接收到信号的线程成功返回,其余调用 pthread_join 的线程则返回错误代码ESRCH。