操作系统实验过程详细解析

操作系统实验过程详细解析
操作系统实验过程详细解析

Dufresne

改变从现在开始!

?博客园

?闪存

?首页

?新随笔

?联系

?管理

?订阅

随笔- 126 文章- 0 评论- 61 Linux中fork()函数详解

linux中fork()函数详解(原创!!实例讲解)(转载)

一、fork入门知识

一个进程,包括代码、数据和分配给进程的资源。fork()函数通过系统调用创建一个与原来进程几乎完全相同的进程,

也就是两个进程可以做完全相同的事,但如果初始参数或者传入的变量不同,两个进程也可以做不同的事。

一个进程调用fork()函数后,系统先给新的进程分配资源,例如存储数据和代码的空间。然后把原来的进程的所有值都

复制到新的新进程中,只有少数值与原来的进程的值不同。相当于克隆了一个自己。

我们来看一个例子:

[cpp]view plaincopy

1./*

2. * fork_test.c

3. * version 1

4. * Created on: 2010-5-29

5. * Author: wangth

6. */

7.#include

8.#include

9.int main ()

10.{

11. pid_t fpid; //fpid表示fork函数返回的值

12. int count=0;

13. fpid=fork();

14. if (fpid < 0)

15. printf("error in fork!");

16. else if (fpid == 0) {

17. printf("i am the child process, my process id is %d/n",ge

tpid());

18. printf("我是爹的儿子/n");//对某些人来说中文看着更直白。

19. count++;

20. }

21. else {

22. printf("i am the parent process, my process id is %d/n",

getpid());

23. printf("我是孩子他爹/n");

24. count++;

25. }

26. printf("统计结果是: %d/n",count);

27. return 0;

28.}

运行结果是:

i am the child process, my process id is 5574

我是爹的儿子

统计结果是: 1

i am the parent process, my process id is 5573

我是孩子他爹

统计结果是: 1

在语句fpid=fork()之前,只有一个进程在执行这段代码,但在这条语句之后,就变成两个进程在执行了,这两个进程的几乎完全相同,

将要执行的下一条语句都是if(fpid<0)……

为什么两个进程的fpid不同呢,这与fork函数的特性有关。

fork调用的一个奇妙之处就是它仅仅被调用一次,却能够返回两次,它可能有三种不同的返回值:

1)在父进程中,fork返回新创建子进程的进程ID;

2)在子进程中,fork返回0;

3)如果出现错误,fork返回一个负值;

在fork函数执行完毕后,如果创建新进程成功,则出现两个进程,一个是子进程,一个是父进程。在子进程中,fork函数返回0,在父进程中,

fork返回新创建子进程的进程ID。我们可以通过fork返回的值来判断当前进程是子进程还是父进程。

引用一位网友的话来解释fpid的值为什么在父子进程中不同。“其实就相当于链表,进程形成了链表,父进程的fpid(p 意味point)指向子进程的进程id,因为子进程没有子进程,所以其fpid为0.

fork出错可能有两种原因:

1)当前的进程数已经达到了系统规定的上限,这时errno的值被设置为E AGAIN。

2)系统内存不足,这时errno的值被设置为ENOMEM。

创建新进程成功后,系统中出现两个基本完全相同的进程,这两个进程执行没有固定的先后顺序,哪个进程先执行要看系统的进程调度策略。

每个进程都有一个独特(互不相同)的进程标识符(process ID),可以通过getpid()函数获得,还有一个记录父进程pid的变量,可以通过getppid ()函数获得变量的值。

fork执行完毕后,出现两个进程,

有人说两个进程的内容完全一样啊,怎么打印的结果不一样啊,那是因为判断条件的原因,上面列举的只是进程的代码和指令,还有变量啊。

执行完fork后,进程1的变量为count=0,fpid!=0(父进程)。进程2的变量为count=0,fpid=0(子进程),这两个进程的变量都是独立的,

存在不同的地址中,不是共用的,这点要注意。可以说,我们就是通过fpid来识别和操作父子进程的。

还有人可能疑惑为什么不是从#include处开始复制代码的,这是因为fork 是把进程当前的情况拷贝一份,执行fork时,进程已经执行完了int count=0; fork只拷贝下一个要执行的代码到新的进程。

二、fork进阶知识

先看一份代码:

[cpp]view plaincopy

1./*

2. * fork_test.c

3. * version 2

4. * Created on: 2010-5-29

5. * Author: wangth

6. */

7.#include

8.#include

9.int main(void)

10.{

11. int i=0;

12. printf("i son/pa ppid pid fpid/n");

13. //ppid指当前进程的父进程pid

14. //pid指当前进程的pid,

15. //fpid指fork返回给当前进程的值

16. for(i=0;i<2;i++){

17. pid_t fpid=fork();

18. if(fpid==0)

19. printf("%d child %4d %4d %4d/n",i,getppid(),getpid

(),fpid);

20. else

21. printf("%d parent %4d %4d %4d/n",i,getppid(),getpid

(),fpid);

22. }

23. return 0;

24.}

运行结果是:

i son/pa ppid pid fpid

0 parent 2043 3224 3225

0 child 3224 3225 0

1 parent 2043 3224 3226

1 parent 3224 3225 3227

1 child 1 3227 0

1 child 1 3226 0

这份代码比较有意思,我们来认真分析一下:

第一步:在父进程中,指令执行到for循环中,i=0,接着执行fork,fork 执行完后,系统中出现两个进程,分别是p3224和p3225

(后面我都用pxxxx表示进程id为xxxx的进程)。可以看到父进程p3224的父进程是p2043,子进程p3225的父进程正好是p3224。我们用一个链表来表示这个关系:

p2043->p3224->p3225

第一次fork后,p3224(父进程)的变量为i=0,fpid=3225(fork函数在父进程中返向子进程id),代码内容为:

[c-sharp]view plaincopy

1.for(i=0;i<2;i++){

2. pid_t fpid=fork();//执行完毕,i=0,fpid=3225

3. if(fpid==0)

4. printf("%d child %4d %4d %4d/n",i,getppid(),getpid(),f

pid);

5. else

6. printf("%d parent %4d %4d %4d/n",i,getppid(),getpid(),

fpid);

7.}

8.return 0;

p3225(子进程)的变量为i=0,fpid=0(fork函数在子进程中返回0),代码内容为:

[c-sharp]view plaincopy

1.for(i=0;i<2;i++){

2. pid_t fpid=fork();//执行完毕,i=0,fpid=0

3. if(fpid==0)

4. printf("%d child %4d %4d %4d/n",i,getppid(),getpid(),f

pid);

5. else

6. printf("%d parent %4d %4d %4d/n",i,getppid(),getpid(),

fpid);

7.}

8.return 0;

所以打印出结果:

0 parent 2043 3224 3225

0 child 3224 3225 0

第二步:假设父进程p3224先执行,当进入下一个循环时,i=1,接着执行fork,系统中又新增一个进程p3226,对于此时的父进程,

p2043->p3224(当前进程)->p3226(被创建的子进程)。

对于子进程p3225,执行完第一次循环后,i=1,接着执行fork,系统中新增一个进程p3227,对于此进程,p3224->p3225(当前进程)->p3227(被创建的子进程)。

从输出可以看到p3225原来是p3224的子进程,现在变成p3227的父进程。父子是相对的,这个大家应该容易理解。只要当前进程执行了fork,该进程就变成了父进程了,就打印出了parent。

所以打印出结果是:

1 parent 2043 3224 3226

1 parent 3224 3225 3227

第三步:第二步创建了两个进程p3226,p3227,这两个进程执行完print f函数后就结束了,因为这两个进程无法进入第三次循环,无法fork,该执行r eturn 0;了,其他进程也是如此。

以下是p3226,p3227打印出的结果:

1 child 1 3227 0

1 child 1 3226 0

细心的读者可能注意到p3226,p3227的父进程难道不该是p3224和p3 225吗,怎么会是1呢?这里得讲到进程的创建和死亡的过程,

在p3224和p3225执行完第二个循环后,main函数就该退出了,也即进程该死亡了,因为它已经做完所有事情了。p3224和p3225死亡后,

p3226,p3227就没有父进程了,这在操作系统是不被允许的,所以p3226,p3227的父进程就被置为p1了,p1是永远不会死亡的,至于为什么,

这里先不介绍,留到“三、fork高阶知识”讲。

总结一下,这个程序执行的流程如下:

这个程序最终产生了3个子进程,执行过6次printf()函数。

我们再来看一份代码:

[cpp]view plaincopy

1./*

2. * fork_test.c

3. * version 3

4. * Created on: 2010-5-29

5. * Author: wangth

6. */

7.#include

8.#include

9.int main(void)

10.{

11. int i=0;

12. for(i=0;i<3;i++){

13. pid_t fpid=fork();

14. if(fpid==0)

15. printf("son/n");

16. else

17. printf("father/n");

18. }

19. return 0;

20.

21.}

它的执行结果是:

father

son

father

father

father

father

son

son

father

son

son

son

father

son

这里就不做详细解释了,只做一个大概的分析。

for i=0 1 2

father father father

son

son father

son

son father father

son

son father

son

其中每一行分别代表一个进程的运行打印结果。

总结一下规律,对于这种N次循环的情况,执行printf函数的次数为2*(1 +2+4+……+2N-1)次,创建的子进程数为1+2+4+……+2N-1个。

(感谢gao_jiawei网友指出的错误,原本我的结论是“执行printf函数的次数为2*(1+2+4+……+2N)次,创建的子进程数为1+2+4+……+2N ”,这是错的)

网上有人说N次循环产生2*(1+2+4+……+2N)个进程,这个说法是不对的,希望大家需要注意。

数学推理见http://202.117.3.13/wordpress/?p=81(该博文的最后)。

同时,大家如果想测一下一个程序中到底创建了几个子进程,最好的方法就是调用printf函数打印该进程的pid,也即调用printf("%d/n",getpid());或者通过printf("+/n");

来判断产生了几个进程。有人想通过调用printf("+");来统计创建了几个进程,这是不妥当的。具体原因我来分析。

老规矩,大家看一下下面的代码:

[cpp]view plaincopy

1./*

2. * fork_test.c

3. * version 4

4. * Created on: 2010-5-29

5. * Author: wangth

6. */

7.#include

8.#include

9.int main() {

10. pid_t fpid;//fpid表示fork函数返回的值

11. //printf("fork!");

12. printf("fork!/n");

13. fpid = fork();

14. if (fpid < 0)

15. printf("error in fork!");

16. else if (fpid == 0)

17. printf("I am the child process, my process id is %d/n", g

etpid());

18. else

19. printf("I am the parent process, my process id is %d/n

", getpid());

20. return 0;

21.}

执行结果如下:

fork!

I am the parent process, my process id is 3361

I am the child process, my process id is 3362

如果把语句printf("fork!/n");注释掉,执行printf("fork!");

则新的程序的执行结果是:

fork!I am the parent process, my process id is 3298 fork!I am the child process, my process id is 3299

程序的唯一的区别就在于一个/n回车符号,为什么结果会相差这么大呢?

这就跟printf的缓冲机制有关了,printf某些内容时,操作系统仅仅是把该内容放到了stdout的缓冲队列里了,并没有实际的写到屏幕上。

但是,只要看到有/n 则会立即刷新stdout,因此就马上能够打印了。

运行了printf("fork!")后,“fork!”仅仅被放到了缓冲里,程序运行到fork时缓冲里面的“fork!”被子进程复制过去了。因此在子进程度stdout

缓冲里面就也有了fork! 。所以,你最终看到的会是fork! 被printf了2次!!!!

而运行printf("fork! /n")后,“fork!”被立即打印到了屏幕上,之后fork到的子进程里的stdout缓冲里不会有fork! 内容。因此你看到的结果会是fork!

被printf了1次!!!!

所以说printf("+");不能正确地反应进程的数量。

大家看了这么多可能有点疲倦吧,不过我还得贴最后一份代码来进一步分析fork函数。

[cpp]view plaincopy

1.#include

2.#include

3.int main(int argc, char* argv[])

4.{

5. fork();

6. fork() && fork() || fork();

7. fork();

8. return 0;

9.}

问题是不算main这个进程自身,程序到底创建了多少个进程。

为了解答这个问题,我们先做一下弊,先用程序验证一下,到此有多少个进程。

[c-sharp]view plaincopy

1.#include

2.int main(int argc, char* argv[])

3.{

4. fork();

5. fork() && fork() || fork();

6. fork();

7. printf("+/n");

8.}

答案是总共20个进程,除去main进程,还有19个进程。

我们再来仔细分析一下,为什么是还有19个进程。

第一个fork和最后一个fork肯定是会执行的。

主要在中间3个fork上,可以画一个图进行描述。

这里就需要注意&&和||运算符。

A&&B,如果A=0,就没有必要继续执行&&B了;A非0,就需要继续执行&&B。

A||B,如果A非0,就没有必要继续执行||B了,A=0,就需要继续执行|| B。

fork()对于父进程和子进程的返回值是不同的,按照上面的A&&B和A||B 的分支进行画图,可以得出5个分支。

加上前面的fork和最后的fork,总共4*5=20个进程,除去main主进程,就是19个进程了。

三、fork高阶知识

这一块我主要就fork函数讲一下操作系统进程的创建、死亡和调度等。因为时间和精力限制,我先写到这里,下次找个时间我争取把剩下的内容补齐。

原文地址:https://www.360docs.net/doc/eb3726015.html,/jason314/article/details/5640969

分类: Android, Linux, 系统

标签: Linux fork process

绿色通道:好文要顶关注我收藏该文与我联系

Dufresne

关注- 13

粉丝- 173

+加关注

9

(请您对文章做出评价)

?上一篇:Android系统启动过程

?下一篇:Win7与Ubuntu双系统时卸载Ubuntu的方法

posted @ 2012-08-31 10:00 Dufresne阅读(26048) 评论(4) 编辑收藏

评论

#1楼2014-03-30 18:39 | 小赵同学

啊,几个fork在一起我就晕了,一个套一个的。

支持(0)反对(0)

#2楼2014-04-14 14:59 | huangzh198

我怎么都想不懂,既然fork复制的是父进程的,那按照汇编代码的角度来看,我第一次fork之后,执行的是后面的,

那打印出来的i 应该是

0 1

1

0 1

1

这样的组合,而不是先打印两次0,之后再打印各自的1两次*2

支持(1)反对(0)

#3楼2014-10-06 15:57 | 小昌昌

最后一道题目,按照你图里面的分析,一个fork_1就同时创建了两个子进程,process_gen2_1和process_gen2_2,这怎么解释啊?

支持(0)反对(0)

#4楼2014-10-20 20:08 | smileshitou

你代码中的回车符错了吧? 应该为\n

支持(0)反对(0)

刷新评论刷新页面返回顶部注册用户登录后才能发表评论,请登录或注册,访问网站首页。

【免费课程】分享:Fiddler工具使用

【推荐】50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库

融云,免费为你的App加入IM功能——让你的App“聊”起来!!

写“听云”原创博文,赢取iPhone 6超级大奖

最新IT新闻:

·硅谷归来:硅谷的自由精神和黑客文化

·360周鸿祎:互联网带来的十大警示

·硅谷风投新投资理念:对赢家绝对关注

·小米为何固守中低端,不愿进军高端市场?

·暴雪:再用外挂永久封号!

?更多新闻...

最新知识库文章:

·大数据在服务器运营中的应用

·禅意设计:网络简洁设计的缘起和未来

·通过一组RESTful API暴露CQRS系统功能

·图数据挖掘浅析

·一像素的恩怨情仇!程序猿与设计狮之间的那些事儿

?更多知识库文章...

昵称:Dufresne 园龄:3年2个月

粉丝:173

关注:13

<

搜索

常用链接

?我的随笔

?我的评论

?我的参与

?最新评论

?我的标签

?更多链接我的标签

?Android(9)

?设计模式(7)

?Android Ril(4)

?Android Framework RIL(3)

?Adapter(2)

?Telephony(2)

?算法排序(2)

?SIM(2)

?Singleton(1)

?SMS PDU编码(1)

?更多

随笔分类

?Android(33)

?Android FrameWork(26)

?Android 控件(2)

?C/C++(12)

?Java学习(3)

?Linux(19)

?Linux内核学习笔记(11)

?Log & Debug(2)

?Reserved form others(1)

?Socket(3)

?Telephony & RIL(14)

?代码大全学习笔记(4)

?内存管理(1)

?软件方法(4)

?设计模式(22)

?深思总结(5)

?实用工具方法(2)

?数据结构与算法(3)

?通讯协议(7)

?系统(4)

随笔档案

?2013年5月(6)

?2013年4月(4)

?2013年3月(1)

?2013年2月(7)

?2013年1月(5)

?2012年12月(1)

?2012年11月(12)

?2012年10月(6)

?2012年9月(16)

?2012年8月(5)

?2012年7月(1)

?2012年6月(7)

?2012年5月(13)

?2012年4月(6)

?2012年3月(3)

?2012年2月(7)

?2012年1月(9)

?2011年12月(8)

?2011年11月(9)

最新评论

? 1. Re:Linux中fork()函数详解

?你代码中的回车符错了吧? 应该为\n

?--smileshitou ? 2. Re:Linux中fork()函数详解

?最后一道题目,按照你图里面的分析,一个fork_1就同时创建了两个子进程,process_gen2_ 1和process_gen2_2,这怎么解释啊?

?--小昌昌? 3. Re:adb常用命令和logcat使用

?说用处不大的是在搞笑吗?

?--Mister.Z ? 4. Re:通过Socket直接与RILD进行通信

?楼主好,能不能把全部的代码给一份,代码片段看不太明白。谢谢了

?--huojiaguang ? 5. Re:Android学习笔记——Activity的启动和创建

?看到楼主的分析,才知道我对安卓了解的太少了

?--Panda Pan 阅读排行榜

? 1. Android系统启动过程(26103)

? 2. Linux中fork()函数详解(26048)

? 3. Android中JNI的使用方法(23799)

? 4. Android 系统属性SystemProperty分析(19731)

? 5. adb常用命令和logcat使用(18336)

评论排行榜

? 1. Android系统启动过程(8)

? 2. Android中JNI的使用方法(6)

? 3. Android学习笔记——Activity的启动和创建(5)

? 4. Linux中fork()函数详解(4)

? 5. 通过Socket直接与RILD进行通信(4)

推荐排行榜

? 1. Linux中fork()函数详解(9)

? 2. Android系统启动过程(6)

? 3. Android 系统属性SystemProperty分析(4)

? 4. Android中LocalSocket使用(4)

? 5. Vold工作流程分析学习(3)

Copyright ?2014 Dufresne

计算机操作系统进程调度实验研究报告

计算机操作系统进程调度实验研究报告

————————————————————————————————作者:————————————————————————————————日期:

操作系统实验题:设计一若干并发进程的进程调度程序 一、实验目的 无论是批处理系统、分时系统还是实时系统,用户进程数一般都大于处理机数,这将导致用户进程互相争夺处理机。这就要求进程调度程序按一定的策略,动态地把处理及分配给处于就绪队列中的某一进程,以使之执行。进程调度是处理机管理的核心内容。本实验要求采用最高优先数优先的调度算法(即把处理机分配给优先数最高的进程)和先来先服务算法编写和调试一个简单的进程调度程序。通过本实验可以加深理解有关进程控制块、进程队列的概念。并体会了优先数和先来先服务调度算法的具体实施办法。 二、实验要求 用高级语言编写和调试一个进程调度程序,以加深对进程的概念及进程调度算法的理解. 三、实验内容 进程调度算法:采用最高优先数优先的调度算法(即把处理机分配给优先数最高的进程)和先来先服务算法(将用户作业和就绪进程按提交顺序或变为就绪状态的先后排成队列,并按照先来先服务的方式进行调度处理)。 每个进程有一个进程控制块(PCB)表示。进程控制块可以包含如下信息:进程名、优先数、到达时间、需要运行时间、已用CPU时间、进程状态等等。 进程的优先数及需要的运行时间可以事先人为地指定(也可以由随机数产生)。进程的到达时间为进程输入的时间。 进程的运行时间以时间片为单位进行计算。 每个进程的状态可以是就绪W(Wait)、运行R(Run)、或完成F(Finish)三种状态之一。 就绪进程获得CPU后都只能运行一个时间片。用已占用CPU时间加1来表示。 如果运行一个时间片后,进程的已占用CPU时间已达到所需要的运行时间,则撤消该进程,如果运行一个时间片后进程的已占用CPU时间还未达所需要的运行时间,也就是进程还需要继续运行,此时应将进程的优先数减1(即降低一级),然后把它插入就绪队列等待CPU。 每进行一次调度程序都打印一次运行进程、就绪队列、以及各个进程的PCB,以便进行检查。重复以上过程,直到所要进程都完成为止。 四、实验算法流程

操作系统-Linux课程实验报告

实验、 Linux Ubuntu的安装、创建新的虚拟机VMWare 实验 Shell编程 1.实验目的与内容 通过本实验,了解Linux系统的shell机制,掌握简单的shell编程技巧。 编制简单的Shell程序,该程序在用户登录时自动执行,显示某些提示信息,如“Welcome to Linux”, 并在命令提示符中包含当前时间、当前目录和当前用户名等基本信息。 2.程序源代码清单 #include<> #include int main(){ printf("Hello Linux\n"); int pid; int state; int pfd[2]; pipe(pfd); if (fork()==0){ printf("In the grep progress\n"); dup2(pfd[0],0); close(pfd[0]); close(pfd[1]); execlp("grep","grep","sh",0); perror("exelp grep error"); } esle if(fork()==0){ printf("In the ps progress\n"); dup2(pfd[1],1); close(pfd[0]); close(pfd[1]); execlp("ps","ps","-ef",0); perror("execlp ps -ef"); }

close(pfd[1]); close(pfd[0]); wait(&state); wait(&state); } 实验内核模块 实验步骤: (1).编写内核模块 文件中主要包含init_clock(),exit_clock(),read_clock()三个函数。其中init_clock(),exit_clock()负责将模块从系统中加载或卸载,以及增加或删除模块在/proc中的入口。read_clock()负责产生/proc/clock被读时的动作。 (2).编译内核模块Makefile文件 # Makefile under ifneq ($(KERNELRELEASE),) #kbuild syntax. dependency relationshsip of files and target modules are listed here. obj-m := else PWD := $(shell pwd) KVER ?= $(shell uname -r) KDIR := /lib/modules/$(KVER)/build all: $(MAKE) -C $(KDIR) M=$(PWD) modules clean: rm -rf .*.cmd *.o *. *.ko .tmp_versions *.symvers *.order endif 编译完成之后生成模块文件。 (3).内核模块源代码 #include #include #include #include #include #include #define MODULE #define MODULE_VERSION "" #define MODULE_NAME "clock" struct proc_dir_entry* my_clock; int read_clock(char* page, char** start, off_t off, int count, int* eof, void* data) { int len; struct timeval xtime;

操作系统实验报告_实验五

实验五:管道通信 实验内容: 1.阅读以下程序: #include #include #include main() { int filedes[2]; char buffer[80]; if(pipe(filedes)<0) //建立管道,filedes[0]为管道里的读取端,filedes[1]则为管道的写入端 //成功则返回零,否则返回-1,错误原因存于errno中 err_quit(“pipe error”); if(fork()>0){ char s[ ] = “hello!\n”; close(filedes[0]); //关闭filedes[0]文件 write(filedes[1],s,sizeof(s)); //s所指的内存写入到filedes[1]文件内 close(filedes[1]); //关闭filedes[0]文件 }else{ close(filedes[1]); read(filedes[0],buffer,80); //把filedes[0]文件传送80个字节到buffer缓冲区内 printf(“%s”,buffer); close(filedes[0]); } } 编译并运行程序,分析程序执行过程和结果,注释程序主要语句。

2.阅读以下程序: #include #include #include main() { char buffer[80]; int fd; unlink(FIFO); //删除FIFO文件 mkfifo(FIFO,0666); //FIFO是管道名,0666是权限 if(fork()>0){ char s[ ] = “hello!\n”;

操作系统实验-进程控制

实验一、进程控制实验 1.1 实验目的 加深对于进程并发执行概念的理解。实践并发进程的创建和控制方法。观察和体验进程的动态特性。进一步理解进程生命期期间创建、变换、撤销状态变换的过程。掌握进程控制的方法,了解父子进程间的控制和协作关系。练习Linux 系统中进程创建与控制有关的系统调用的编程和调试技术。 1.2 实验说明 1)与进程创建、执行有关的系统调用说明进程可以通过系统调用fork()创建子进程并和其子进程并发执行.子进程初始的执行映像是父进程的一个复本.子进程可以通过exec()系统调用族装入一个新的执行程序。父进程可以使用wait()或waitpid()系统调用等待子进程的结束并负责收集和清理子进程的退出状态。 fork()系统调用语法: #include pid_t fork(void); fork 成功创建子进程后将返回子进程的进程号,不成功会返回-1. exec 系统调用有一组6 个函数,其中示例实验中引用了execve 系统调用语法: #include int execve(const char *path, const char *argv[], const char * envp[]); path 要装入 的新的执行文件的绝对路径名字符串. argv[] 要传递给新执行程序的完整的命令参数列表(可以为空). envp[] 要传递给新执行程序的完整的环境变量参数列表(可以为空).

Exec 执行成功后将用一个新的程序代替原进程,但进程号不变,它绝不会再返回到调用进程了。如果exec 调用失败,它会返回-1。 wait() 系统调用语法: #include #include pid_t wait(int *status); pid_t waitpid(pid_t pid,int *status,int option); status 用 于保留子进程的退出状态 pid 可以为以下可能值: -1 等待所有PGID 等于PID 的绝对值的子进程 1 等待所有子进程 0 等待所有PGID 等于调用进程的子进程 >0 等待PID 等于pid 的子进程option 规 定了调用waitpid 进程的行为: WNOHANG 没有子进程时立即返回 WUNTRACED 没有报告状态的进程时返回 wait 和waitpid 执行成功将返回终止的子进程的进程号,不成功返回-1。 getpid()系统调用语法: #include #include pid_t getpid(void); pid_t getppid(void); getpid 返回当前进程的进程号,getppid 返回当前进程父进程的进程号 2)与进程控制有关的系统调用说明可以通过信号向一个进程发送消息以控制进程的 行为。信号是由中断或异常事件引发的,如:键盘中断、定时器中断、非法内存引

计算机操作系统实验课实验报告

实验报告 实验课程: 计算机操作系统学生姓名:XXX 学号:XXXX 专业班级:软件 2014年12月25日

目录 实验一熟悉Windows XP中的进程和线程.. 3实验二进程调度 (7) 实验三死锁避免—银行家算法的实现 (18) 实验四存储管理 (24)

实验一熟悉Windows XP中的进程和线程 一、实验名称 熟悉Windows XP中的进程和线程 二、实验目的 1、熟悉Windows中任务管理器的使用。 2、通过任务管理器识别操作系统中的进程和线程的相关信息。 3、掌握利用spy++.exe来察看Windows中各个任务的更详细信息。 三、实验结果分析 1、启动操作系统自带的任务管理器: 方法:直接按组合键Ctrl+Alt+Del,或者是在点击任务条上的“开始”“运行”,并输入“taskmgr.exe”。

2、调整任务管理器的“查看”中的相关设置,显示关于进程的以下各项信息,并 完成下表: 表一:统计进程的各项主要信息 3、启动办公软件“Word”,在任务管理器中找到该软件的登记,并将其结束掉。再

从任务管理器中分别找到下列程序:winlogon.exe、lsass.exe、csrss.exe、smss.exe,试着结束它们,观察到的反应是任务管理器无法结束进程, 原因是该系统是系统进程。 4、在任务管理器中找到进程“explorer.exe”,将之结束掉,并将桌面上你打开的所 有窗口最小化,看看你的计算机系统起来什么样的变化桌面上图标菜单都消失了、得到的结论explorer.exe是管理桌面图标的文件(说出explorer.exe进程的作用)。 5、运行“spy++.exe”应用软件,点击按钮“”,切换到进程显示栏上,查看进 程“explorer.exe”的各项信息,并填写下表: 进程:explorer.exe 中的各个线程

操作系统实验报告

操作系统教程 实 验 指 导 书 姓名: 学号: 班级:软124班 指导老师:郭玉华 2014年12月10日

实验一WINDOWS进程初识 1、实验目的 (1)学会使用VC编写基本的Win32 Consol Application(控制台应用程序)。 (2)掌握WINDOWS API的使用方法。 (3)编写测试程序,理解用户态运行和核心态运行。 2、实验内容和步骤 (1)编写基本的Win32 Consol Application 步骤1:登录进入Windows,启动VC++ 6.0。 步骤2:在“FILE”菜单中单击“NEW”子菜单,在“projects”选项卡中选择“Win32 Consol Application”,然后在“Project name”处输入工程名,在“Location”处输入工程目录。创建一个新的控制台应用程序工程。 步骤3:在“FILE”菜单中单击“NEW”子菜单,在“Files”选项卡中选择“C++ Source File”, 然后在“File”处输入C/C++源程序的文件名。 步骤4:将清单1-1所示的程序清单复制到新创建的C/C++源程序中。编译成可执行文件。 步骤5:在“开始”菜单中单击“程序”-“附件”-“命令提示符”命令,进入Windows“命令提示符”窗口,然后进入工程目录中的debug子目录,执行编译好的可执行程序: E:\课程\os课\os实验\程序\os11\debug>hello.exe 运行结果 (如果运行不成功,则可能的原因是什么?) : 有可能是因为DOS下路径的问题 (2)计算进程在核心态运行和用户态运行的时间 步骤1:按照(1)中的步骤创建一个新的“Win32 Consol Application”工程,然后将清单1-2中的程序拷贝过来,编译成可执行文件。 步骤2:在创建一个新的“Win32 Consol Application”工程,程序的参考程序如清单1-3所示,编译成可执行文件并执行。 步骤3:在“命令提示符”窗口中运行步骤1中生成的可执行文件,测试步骤2中可执行文件在核心态运行和用户态运行的时间。 E:\课程\os课\os实验\程序\os12\debug>time TEST.exe 步骤4:运行结果 (如果运行不成功,则可能的原因是什么?) : 因为程序是个死循环程序 步骤5:分别屏蔽While循环中的两个for循环,或调整两个for循环的次数,写出运行结果。 屏蔽i循环: 屏蔽j循环: _______________________________________________________________________________调整循环变量i的循环次数:

操作系统实验报告--实验一--进程管理

实验一进程管理 一、目的 进程调度是处理机管理的核心内容。本实验要求编写和调试一个简单的进程调度程序。通过本实验加深理解有关进程控制块、进程队列的概念,并体会和了解进程调度算法的具体实施办法。 二、实验内容及要求 1、设计进程控制块PCB的结构(PCB结构通常包括以下信息:进程名(进程ID)、进程优先数、轮转时间片、进程所占用的CPU时间、进程的状态、当前队列指针等。可根据实验的不同,PCB结构的内容可以作适当的增删)。为了便于处理,程序中的某进程运行时间以时间片为单位计算。各进程的轮转时间数以及进程需运行的时间片数的初始值均由用户给定。 2、系统资源(r1…r w),共有w类,每类数目为r1…r w。随机产生n进程P i(id,s(j,k),t),0<=i<=n,0<=j<=m,0<=k<=dt为总运行时间,在运行过程中,会随机申请新的资源。 3、每个进程可有三个状态(即就绪状态W、运行状态R、等待或阻塞状态B),并假设初始状态为就绪状态。建立进程就绪队列。 4、编制进程调度算法:时间片轮转调度算法 本程序用该算法对n个进程进行调度,进程每执行一次,CPU时间片数加1,进程还需要的时间片数减1。在调度算法中,采用固定时间片(即:每执行一次进程,该进程的执行时间片数为已执行了1个单位),这时,CPU时间片数加1,进程还需要的时间片数减1,并排列到就绪队列的尾上。 三、实验环境 操作系统环境:Windows系统。 编程语言:C#。 四、实验思路和设计 1、程序流程图

2、主要程序代码 //PCB结构体 struct pcb { public int id; //进程ID public int ra; //所需资源A的数量 public int rb; //所需资源B的数量 public int rc; //所需资源C的数量 public int ntime; //所需的时间片个数 public int rtime; //已经运行的时间片个数 public char state; //进程状态,W(等待)、R(运行)、B(阻塞) //public int next; } ArrayList hready = new ArrayList(); ArrayList hblock = new ArrayList(); Random random = new Random(); //ArrayList p = new ArrayList(); int m, n, r, a,a1, b,b1, c,c1, h = 0, i = 1, time1Inteval;//m为要模拟的进程个数,n为初始化进程个数 //r为可随机产生的进程数(r=m-n) //a,b,c分别为A,B,C三类资源的总量 //i为进城计数,i=1…n //h为运行的时间片次数,time1Inteval为时间片大小(毫秒) //对进程进行初始化,建立就绪数组、阻塞数组。 public void input()//对进程进行初始化,建立就绪队列、阻塞队列 { m = int.Parse(textBox4.Text); n = int.Parse(textBox5.Text); a = int.Parse(textBox6.Text); b = int.Parse(textBox7.Text); c = int.Parse(textBox8.Text); a1 = a; b1 = b; c1 = c; r = m - n; time1Inteval = int.Parse(textBox9.Text); timer1.Interval = time1Inteval; for (i = 1; i <= n; i++) { pcb jincheng = new pcb(); jincheng.id = i; jincheng.ra = (random.Next(a) + 1); jincheng.rb = (random.Next(b) + 1); jincheng.rc = (random.Next(c) + 1); jincheng.ntime = (random.Next(1, 5)); jincheng.rtime = 0;

操作系统实验报告心得体会

操作系统实验报告心得体会 每一次课程设计度让我学到了在平时课堂不可能学到的东西。所以我对每一次课程设计的机会都非常珍惜。不一定我的课程设计能够完成得有多么完美,但是我总是很投入的去研究去学习。所以在这两周的课设中,熬了2个通宵,生物钟也严重错乱了。但是每完成一个任务我都兴奋不已。一开始任务是任务,到后面任务就成了自己的作品了。总体而言我的课设算是达到了老师的基本要求。总结一下有以下体会。 1、网络真的很强大,用在学习上将是一个非常高效的助手。几乎所有的资料都能够在网上找到。从linux虚拟机的安装,到linux的各种基本命令操作,再到gtk的图形函数,最后到文件系统的详细解析。这些都能在网上找到。也因为这样,整个课程设计下来,我浏览的相关网页已经超过了100个(不完全统计)。当然网上的东西很乱很杂,自己要能够学会筛选。 不能决定对或错的,有个很简单的方法就是去尝试。就拿第二个实验来说,编译内核有很多项小操作,这些小操作错了一项就可能会导致编译的失败,而这又是非常要花时间的,我用的虚拟机,编译一次接近3小时。所以要非常的谨慎,尽量少出差错,节省时间。多找个几个参照资料,相互比较,

慢慢研究,最后才能事半功倍。 2、同学间的讨论,这是很重要的。老师毕竟比较忙。对于课程设计最大的讨论伴侣应该是同学了。能和学长学姐讨论当然再好不过了,没有这个机会的话,和自己班上同学讨论也是能够受益匪浅的。大家都在研究同样的问题,讨论起来,更能够把思路理清楚,相互帮助,可以大大提高效率。 3、敢于攻坚,越是难的问题,越是要有挑战的心理。这样就能够达到废寝忘食的境界。当然这也是不提倡熬夜的,毕竟有了精力才能够打持久战。但是做课设一定要有状态,能够在吃饭,睡觉,上厕所都想着要解决的问题,这样你不成功都难。 4、最好在做课设的过程中能够有记录的习惯,这样在写实验报告时能够比较完整的回忆起中间遇到的各种问题。比如当时我遇到我以前从未遇到的段错误的问题,让我都不知道从何下手。在经过大量的资料查阅之后,我对段错误有了一定的了解,并且能够用相应的办法来解决。 在编程中以下几类做法容易导致段错误,基本是是错误地使用指针引起的 1)访问系统数据区,尤其是往系统保护的内存地址写数据,最常见就是给一个指针以0地址 2)内存越界(数组越界,变量类型不一致等) 访问到不属于你的内存区域

操作系统-Linux课程实验报告

实验 1.1、1.2 Linux Ubuntu的安装、创建新的虚拟机VMWare

实验1.3 Shell编程 1.实验目的与容 通过本实验,了解Linux系统的shell机制,掌握简单的shell编程技巧。 编制简单的Shell程序,该程序在用户登录时自动执行,显示某些提示信息,如“Welcome to Linux”, 并在命令提示符中包含当前时间、当前目录和当前用户名等基本信息。 2.程序源代码清单 #include #include int main(){ printf("Hello Linux\n"); int pid; int state; int pfd[2]; pipe(pfd); if (fork()==0){ printf("In the grep progress\n"); dup2(pfd[0],0); close(pfd[0]); close(pfd[1]); execlp("grep","grep","sh",0); perror("exelp grep error");

} esle if(fork()==0){ printf("In the ps progress\n"); dup2(pfd[1],1); close(pfd[0]); close(pfd[1]); execlp("ps","ps","-ef",0); perror("execlp ps -ef"); } close(pfd[1]); close(pfd[0]); wait(&state); wait(&state); } 实验2.3 核模块 实验步骤: (1).编写核模块 文件中主要包含init_clock(),exit_clock(),read_clock()三个函数。其中init_clock(),exit_clock()负责将模块从系统中加载或卸载,以及增加或删除模块在/proc中的入口。read_clock()负责产生/proc/clock被读时的动作。 (2).编译核模块Makefile文件 # Makefile under 2.6.25

操作系统实验报告

操作系统实验报告 实验名称: 系统的引导 所在班级: 指导老师: 老师 实验日期: 2014年3 月29 日

一、实验目的 ◆熟悉hit-oslab实验环境; ◆建立对操作系统引导过程的深入认识; ◆掌握操作系统的基本开发过程; ◆能对操作系统代码进行简单的控制,揭开操作系统的神秘面纱。 二、实验容 1. 阅读《Linux核完全注释》的第6章引导启动程序,对计算机和Linux 0.11的引导过程进行初步的了解。 2. 按照下面的要求改写0.11的引导程序bootsect.s。 3. 有兴趣同学可以做做进入保护模式前的设置程序setup.s。 4. 修改build.c,以便可以使用make BootImage命令 5. 改写bootsect.s主要完成如下功能: bootsect.s能在屏幕上打印一段提示信息XXX is booting...,其中XXX是你给自己的操作系统起的名字,例如LZJos、Sunix等。 6. 改写setup.s主要完成如下功能: bootsect.s能完成setup.s的载入,并跳转到setup.s开始地址执行。而setup.s 向屏幕输出一行"Now we are in SETUP"。setup.s能获取至少一个基本的硬件参数(如存参数、显卡参数、硬盘参数等),将其存放在存的特定地址,并输出到屏幕上。setup.s不再加载Linux核,保持上述信息显示在屏幕上即可。 三、实验环境

本实验使用的系统是windows系统或者是Linux系统,需要的材料是osexp。 四、实验步骤 1. 修改bootsect.s中的提示信息及相关代码; 到osexp\Linux-0.11\boot目录下会看到图1所示的三个文件夹,使用UtraEdit 打开该文件。将文档中的98行的mov cx,#24修改为mov cx,#80。同时修改文档中的第246行为图2所示的情形。 图1图2 图3 2. 在目录linux-0.11\boot下,分别用命令as86 -0 -a -o bootsect.obootsect.s和 ld86 -0 -s -obootsectbootsect.o编译和bootsect.s,生成bootsect文件; 在\osexp目录下点击MinGW32.bat依此输入下面的命令: cd linux-0.11 cd boot as86 -0 -a -o bootsect.obootsect.s ld86 -0 -s -o bootsectbootsect.o

操作系统实验报告

操作系统教程实验报告 专业班级 学号 姓名 指导教师

实验一WINDOWS进程初识 1、实验目的 (1)学会使用VC编写基本的Win32 Consol Application(控制台应用程序)。 (2)掌握WINDOWS API的使用方法。 (3)编写测试程序,理解用户态运行和核心态运行。 2、实验内容和步骤 (1)编写基本的Win32 Consol Application 步骤1:登录进入Windows,启动VC++ 6.0。 步骤2:在“FILE”菜单中单击“NEW”子菜单,在“projects”选项卡中选择“Win32 Consol Application”,然后在“Project name”处输入工程名,在“Location”处输入工程目录。创建一个新的控制台应用程序工程。 步骤3:在“FILE”菜单中单击“NEW”子菜单,在“Files”选项卡中选择“C++ Source File”, 然后在“File”处输入C/C++源程序的文件名。 步骤4:将清单1-1所示的程序清单复制到新创建的C/C++源程序中。编译成可执行文件。 步骤5:在“开始”菜单中单击“程序”-“附件”-“命令提示符”命令,进入Windows “命令提示符”窗口,然后进入工程目录中的debug子目录,执行编译好的可执行程序:E:\课程\os课\os实验\程序\os11\debug>hello.exe 运行结果 (如果运行不成功,则可能的原因是什么?) : (2)计算进程在核心态运行和用户态运行的时间 步骤1:按照(1)中的步骤创建一个新的“Win32 Consol Application”工程,然后将清单1-2中的程序拷贝过来,编译成可执行文件。 步骤2:在创建一个新的“Win32 Consol Application”工程,程序的参考程序如清单1-3所示,编译成可执行文件并执行。 步骤3:在“命令提示符”窗口中运行步骤1中生成的可执行文件,测试步骤2中可执行文件在核心态运行和用户态运行的时间。 E:\课程\os课\os实验\程序\os12\debug>time TEST.exe 步骤4:运行结果 (如果运行不成功,则可能的原因是什么?) : 步骤5:分别屏蔽While循环中的两个for循环,或调整两个for循环的次数,写出运行结果。 屏蔽i循环:

操作系统课程设计实验报告

河北大学工商学院 课程设计 题目:操作系统课程设计 学部信息学部 学科门类电气信息 专业计算机 学号2011482370 姓名耿雪涛 指导教师朱亮 2013 年6月19日

主要内容 一、设计目的 通过模拟操作系统的实现,加深对操作系统工作原理理解,进一步了解操作系统的实现方法,并可练习合作完成系统的团队精神和提高程序设计能力。 二、设计思想 实现一个模拟操作系统,使用VB、VC、CB等windows环境下的程序设计语言,以借助这些语言环境来模拟硬件的一些并行工作。模拟采用多道程序设计方法的单用户操作系统,该操作系统包括进程管理、存储管理、设备管理、文件管理和用户接口四部分。 设计模板如下图: 注:本人主要涉及设备管理模块

三、设计要求 设备管理主要包括设备的分配和回收。 ⑴模拟系统中有A、B、C三种独占型设备,A设备1个,B设备2个,C设备2个。 ⑵采用死锁的预防方法来处理申请独占设备可能造成的死锁。 ⑶屏幕显示 注:屏幕显示要求包括:每个设备是否被使用,哪个进程在使用该设备,哪些进程在等待使用该设备。 设备管理模块详细设计 一、设备管理的任务 I/O设备是按照用户的请求,控制设备的各种操作,用于完成I/O 设备与内存之间的数据交换(包括设备的分配与回收,设备的驱动管理等),最终完成用户的I/O请求,并且I/O设备为用户提供了使用外部设备的接口,可以满足用户的需求。 二、设备管理函数的详细描述 1、检查设备是否可用(主要代码) public bool JudgeDevice(DeviceType type) { bool str = false; switch (type) { case DeviceType.a: {

操作系统实验报告

操作系统实验报告 Document number:NOCG-YUNOO-BUYTT-UU986-1986UT

许昌学院 《操作系统》实验报告书学号: 姓名:闫金科 班级:14物联网工程 成绩: 2016年02月

实验一Linux的安装与配置 一、实验目的 1.熟悉Linux系统的基本概念,比如Linux发行版、宏内核、微内核等。 2.掌握Linux系统的安装和配置过程,初步掌握Linux系统的启动和退出方 法。 3.熟悉Linux系统的文件系统结构,了解Linux常用文件夹的作用。 二、实验内容 1.从网络上下载VMware软件和两个不同Linux发行版镜像文件。 2.安装VMware虚拟机软件。 3.在VMware中利用第一个镜像文件完成第一个Linux的安装,期间完成网络 信息、用户信息、文件系统和硬盘分区等配置。 4.在VMware中利用第二个镜像文件完成第二个Linux的安装,并通过LILO或 者GRUB解决两个操作系统选择启动的问题。 5.启动Linux系统,打开文件浏览器查看Linux系统的文件结构,并列举出 Linux常用目录的作用。 三、实验过程及结果 1、启动VMware,点击新建Linux虚拟机,如图所示: 2、点击下一步,选择经典型,点击下一步在选择客户机页面选择 Linux,版本选择RedHatEnterpriseLinux5,如图所示: 3、点击下一步创建虚拟机名称以及所要安装的位置,如图所示: 4、点击下一步,磁盘容量填一个合适大小,此处选择默认值大小 10GB,如图所示: 5、点击完成,点击编辑虚拟机设置,选择硬件选项中的CD-ROM (IDE...)选项,在右侧连接中选择“使用ISO镜像(I)”选项,点 击“浏览”,找到Linux的镜像文件,如图所示:

操作系统原理实验报告(终版)

操作系统原理实验报告(终版)

————————————————————————————————作者:————————————————————————————————日期:

[键入文字] XX学校 实验报告 课程名称: 学院: 专业班: 姓名: 学号: 指导教师: 2011 年3 月

目录 实验1 进程管理 (3) 一、实验目的 (3) 二、实验内容 (3) 三、实验要求 (3) 四、程序说明和程序流程图 (4) 五、程序代码 (5) 六、程序运行结果及分析 (7) 七.指导教师评议 (8) 实验2 进程通信 (9) 一、实验目的 (9) 二、实验内容 (9) 三、实验要求 (9) 四、程序说明和程序流程图 (9) 五、程序代码 (11) 七.指导教师评议 (14) 实验3 存储管理 (15) 一、实验目的 (15) 二、实验内容 (15) 三、实验要求 (15) 四、程序说明和程序流程图 (16) 六、程序运行结果及分析 (23)

七.指导教师评议 (23) 实验4 文件系统 (24) 一、实验目的 (24) 二、实验内容 (24) 三、实验要求 (24) 四、程序说明和程序流程图 (24) 五、程序代码 (26) 六、程序运行结果及分析 (26) 七.指导教师评议 (27)

实验1 进程管理 一、实验目的 1. 弄清进程和程序的区别,加深对进程概念的理解。 2. 了解并发进程的执行过程,进一步认识并发执行的实质。 3. 掌握解决进程互斥使用资源的方法。 二、实验内容 1. 管道通信 使用系统调用pipe( )建立一个管道,然后使用系统调用fork( )创建2个子进程p1和p2。这2个子进程分别向管道中写入字符串:“Child process p1 is sending message!”和“Child process p2 is sending message!”,而父进程则从管道中读出来自两个子进程的信息,并显示在屏幕上。 2. 软中断通信 使用系统调用fork( )创建2个子进程p1和p2,在父进程中使用系统调用signal( )捕捉来自键盘上的软中断信号SIGINT(即按Ctrl-C),当捕捉到软中断信号SIGINT后,父进程使用系统调用kill( )分别向2个子进程发出软中断信号SIGUSR1和SIGUSR2,子进程捕捉到信号后分别输出信息“Child process p1 is killed by parent!”和“Child process p2 is killed by parent!”后终止。而父进程等待2个子进程终止后,输出信息“Parent process is killed!”后终止。 三、实验要求 1. 根据实验内容编写C程序。 2. 上机调试程序。 3. 记录并分析程序运行结果。

操作系统-进程管理实验报告

实验一进程管理 1.实验目的: (1)加深对进程概念的理解,明确进程和程序的区别; (2)进一步认识并发执行的实质; (3)分析进程争用资源的现象,学习解决进程互斥的方法; (4)了解Linux系统中进程通信的基本原理。 2.实验预备内容 (1)阅读Linux的sched.h源码文件,加深对进程管理概念的理解; (2)阅读Linux的fork()源码文件,分析进程的创建过程。 3.实验内容 (1)进程的创建: 编写一段程序,使用系统调用fork() 创建两个子进程。当此程序运行时,在系统中有一个父进程和两个子进程活动。让每一个进程在屏幕上显示一个字符:父进程显示字符“a”,子进程分别显示字符“b”和“c”。试观察记录屏幕上的显示结果,并分析原因。 源代码如下: #include #include #include #include #include int main(int argc,char* argv[]) { pid_t pid1,pid2; pid1 = fork(); if(pid1<0){ fprintf(stderr,"childprocess1 failed"); exit(-1); } else if(pid1 == 0){ printf("b\n"); } 1/11

else{ pid2 = fork(); if(pid2<0){ fprintf(stderr,"childprocess1 failed"); exit(-1); } else if(pid2 == 0){ printf("c\n"); } else{ printf("a\n"); sleep(2); exit(0); } } return 0; } 结果如下: 分析原因: pid=fork(); 操作系统创建一个新的进程(子进程),并且在进程表中相应为它建立一个新的表项。新进程和原有进程的可执行程序是同一个程序;上下文和数据,绝大部分就是原进程(父进程)的拷贝,但它们是两个相互独立的进程!因此,这三个进程哪个先执行,哪个后执行,完全取决于操作系统的调度,没有固定的顺序。 (2)进程的控制 修改已经编写的程序,将每个进程输出一个字符改为每个进程输出一句话,再观察程序执行时屏幕上出现的现象,并分析原因。 将父进程的输出改为father process completed 2/11

操作系统实验报告

操作系统实验报告 银行家算法 班级:计算机()班 姓名:李君益 学号:(号) 提交日期: 指导老师: 林穗 一、设计题目 加深了解有关资源申请、避免死锁等概念,并体会和了解死锁和避免死锁的具体实施方法。 要求编写和调试一个系统动态分配资源的简单模拟程序,观察死锁产生的条件,并采用银行家算法,有效的防止和避免死锁的发生。 二、设计要求

内容: 编制银行家算法通用程序,并检测思考题中所给状态的安全性。 要求: (1)下列状态是否安全?(三个进程共享个同类资源) 进程已分配资源数最大需求数 (状态) (状态) (2)考虑下列系统状态 分配矩阵最大需求矩阵可用资源矩阵 问系统是否安全?若安全就给出所有的安全序列。若进程请求(),可否立即分配? 三、设计分析 一.关于操作系统的死锁 .死锁的产生 计算机系统中有许多独占资源,他们在任一时刻只能被一个进程使用,如磁带机,绘图仪等独占型外围设备,或进程表,临界区等软件资源。两个进程同时向一台打印机输出将导致一片混乱,两个进程同时进入临界区将导致数据库错误乃至程序崩溃。正因为这些原因,所有操作系统都具有授权一个进程独立访问某一辞源的能力。一个进程需要使用独占型资源必须通过以下的次序: ●申请资源 ●使用资源 ●归还资源 若申请施资源不可用,则申请进程进入等待状态。对于不同的独占资源,进程等待的方式是有差别的,如申请打印机资源、临界区资源时,申请失败将一位这阻塞申请进程;而申请打开文件文件资源时,申请失败将返回一个错误码,由申请进程等待一段时间之后重试。只得指出的是,不同的操作系统对于同一种资源采取的等待方式也是有差异的。 在许多应用中,一个进程需要独占访问多个资源,而操作系统允许多个进程并发执行共享系统资源时,此时可能会出现进程永远被阻塞的现象。这种现象称为“死锁”。 2.死锁的定义 一组进程处于死锁状态是指:如果在一个进程集合中的每个进程都在等待只能由该集合中的其他一个进程才能引发的时间,则称一组进程或系统此时发生了死锁。 .死锁的防止 .死锁产生的条件: ●互斥条件

操作系统实验报告1

操作系统 实验报告 班号:1303107 学号:1130310726 姓名:蔡鹏

1.请简述head.s 的工作原理。 head.s实在32位保护模式下运行的。我认为这段程序主要包括两个部分:1.初始化设置。2.任务执行与切换。 初始设置主要包括了:1.设置GDT表2.设置系统定时芯片3. 设置IDT表(0x08时钟中断和0x80系统调用中断)4.切换到任务0执行 任务切换和执行包括了:1.任务0和任务1 , 2.时钟中断, 3.系统中断 两个任务的在LDT中代码段和数据段描述符的内容都设置为:基地址0x0000;段限长值为0x03ff,实际段长度为4MB。因此在线性地址空间中这个?内核?的代码和数据段与任务的代码和数据段都从线性地址0开始并且由于没有采用分页机制,所以他们都直接对应物理地址0开始处。 为了每隔10毫秒切换运行的任务,head.s程序中把定时器芯片8253的通道0设置成每隔10毫秒就向中断控制芯片8259A发送一个时钟中断请求信号。PC机的ROM BIOS开机时已经在8259A中把时钟中断请求信号设置成中断向量8,因此我们需要在中断8的处理过程中执行任务切换操作。任务切换的实现是查看current变量中的当前运行的任务号,如果为0,就利用任务1的TSS选择符作为操作数执行远跳转指令,从而切换到任务1中,否则反之。

每个任务在执行时,会首先把一个字符的ASCII码放入寄存器AL中,然后调用系统中断调用int 0x80,而该系统调用处理过程则会调用一个简单的字符写屏子程序,把寄存器AL中的字符显示在屏幕上,同时把字符显示的屏幕的下一个位置记录下来,作为下一次显示字符用。在显示过一个字符后,任务代码会使用循环语句延迟一段时间,然后又跳转到任务代码开始处继续循环执行,直到运行了10毫秒而发生了定时中断,从而代码会切换到另一个任务执行。对于任务A,寄存器AL中始终存放字符‘A’,而任务B运行时AL中始终存放字符‘B’。因此程序运行时我们将看到一连串的‘A’和一连串的‘B’间隔的连续不断的显示在屏幕上。若出现了一个‘C’,是由于PC机偶然产生了一个不是时钟中断和系统调用中断的其他中断。因为我们已经在程序中给所有其他中断安装了一个默认中断处理程序。当出现一个其他中断时,系统就会运行这个中断处理程序,于是就会在屏幕上显示一个‘C’,然后退出中断。 4.请记录head.s 的内存分布状况,写明每个数据段,代码段,栈段 的起始与终止的内存地址。

操作系统实验二

操作系统实验实验二进程管理 学号 1215108019 姓名克帆 学院信息学院 班级 12电子2

实验目的 1、理解进程的概念,明确进程和程序的区别。 2、理解并发执行的实质。 3、掌握进程的创建、睡眠、撤销等进程控制方法。 实验容与要求 基本要求:用C语言编写程序,模拟实现创建新的进程;查看运行进程;换出某个进程;杀死进程等功能。 实验报告容 1、进程、进程控制块等的基本原理。 进程是现代操作系统中的一个最基本也是最重要的概念,掌握这个概念对于理解操作系统实质,分析、设计操作系统都有其非常重要的意义。为了强调进程的并发性和动态性,可以给进程作如下定义:进程是可并发执行的程序在一个数据集合上的运行过程,是系统进行资源分配和调度的一个独立单位。 进程又就绪、执行、阻塞三种基本状态,三者的变迁图如下: 由于多个程序并发执行,各程序需要轮流使用CPU,当某程序不在CPU上运行时,必须保留其被中断的程序的现场,包括:断点地址、程序状态字、通用寄存器的容、堆栈容、程序当前状态、程序的大小、运行时间等信息,以便程序再次获得CPU时,能够正确执行。为了保存这些容,需要建立—个专用数据结构,我们称这个数据结构为进程控制块PCB (Process Control Block)。 进程控制块是进程存在的惟一标志,它跟踪程序执行的情况,表明了进程在当前时刻的状态以及与其它进程和资源的关系。当创建一个进程时,实际上就是为其建立一个进程控制块。 在通常的操作系统中,PCB应包含如下一些信息: ①进程标识信息。为了标识系统中的各个进程,每个进程必须有惟一的标识名或标 识数。 ②位置信息。指出进程的程序和数据部分在存或外存中的物理位置。 ③状态信息。指出进程当前所处的状态,作为进程调度、分配CPU的依据。 ④进程的优先级。一般根据进程的轻重缓急其它信息。 这里给出的只是一般操作系统中PCB所应具有的容,不同操作系统的PCB结构是不同的,我们将在2.8节介绍Linux系统的PCB结构。

相关文档
最新文档