【操作系统】实验二 进程控制实验

本文详细介绍了Linux操作系统中进程控制实验的内容,包括进程状态命令、进程控制命令和系统调用的使用,通过实例展示了如何操作进程、理解进程状态转换以及线程异步并发。实验涉及的知识点有助于深入理解进程管理与C语言编程。
摘要由CSDN通过智能技术生成

目录

实验目的及要求

实验环境

实验原理

1.进程状态命令

2.进程控制命令

3.  进程控制相关的系统调用

实验内容与步骤

实验结果与分析

1.实例一

2.实例二

3.实例三

4.实例四

5.实例五

6.实例六

7.实例七

8.实例八

9. 选做题

10. 线程异步并发实验

总结

实验收获及体会


本人一直想找时间系统整理一下之前做过的一些实验,便于后续用到的时候可以尽快的使用,po出来也便于大家交流学习,有问题欢迎交流指正,与诸君共勉!

操作系统实验二,进程控制。

实验目的及要求

1. 理解进程的状态转换,了解进程控制函数:fork、wait/waitpid函数。

2. 掌握系统调用的简单编程。

3. 进一步掌握C语言程序的开发方法,阅读、调试C程序并编写简单的进程创建程序。

4. 通过有关进程控制的应用实例,深刻理解进程的管理过程。

实验环境

VMware虚拟机、CentOS操作系统

实验原理

1.进程状态命令

表1 Linux中的进程状态命令

ps命令

ps输出中的标题

命令

作用

字段

解释

ps

显示所有正在执行的进程

PID

进程标识号

ps-x

显示所有程序,不以终端机来区分

TTY

开始这个进程的终端

ps-aux

显示所有进程和其状态

TIME

进程的累计执行时间,以分和秒表示

ps aux|grep xxx

 显示进程名为xxx的进程的状态

COMMAND

正在执行的命令名

2.进程控制命令

(1)kill <进程标识符>,向进程发送终止信号,撤消进程。

(2)创建后台进程:在命令后输入后台命令符&,如$ sleep 50 & ,表示要创建一个睡眠时间为50秒的进程。

3.  进程控制相关的系统调用

(1)fork()。创建一个子进程,用它创建的子进程是fork调用者进程(即父进程)的复制品,即进程映象。除了进程标识符以及与进程特性有关的一些参数外,其它与父进程相同,与父进程共享文本段和打开的文件,并都受进程调度程序的调度。(一次调用两个返回结果)

如果创建进程失败,则fork()返回值为-1;如果创建进程成功,则在父进程中返回值是子进程号,子进程中返回的值是0。m=fork()。

(2)wait()。父进程处于阻塞(或等待)状态,等待子进程执行完成终止后继续工作(会令调用者阻塞直至某个子进程终止)。其返回值为子进程号。n=wait()。wait的返回值是终止进程的进程ID。

(3)waitpid()。等待一个或某个子进程退出函数。通常,父进程可以调用该函数,等待其所有子进程退出后才退出,保证所有任务顺利完成,具有指定性。

(4)exit()。子进程自我终止,释放所占资源,通知父进程可以删除自己。此时它的状态变成P_state=SZOMB。

(5)getpid()。获得进程的进程号,为正整数。p=getpid()。getppid()

实验内容与步骤

1.   在Linux下,top命令是Linux下常用的性能分析工具,能够实时显示系统中各个进程的资源占用状况,类似于Windows的任务管理器。(用来看查看进程耗费cpu和内存的情况)[ctr+c退出]

2.   在Linux下,熟悉进程状态命令(ps)的使用;编写一些简单代码来观察各种情况下,Linux进程的状态,进一步理解进程的状态及转换机制。

图2 Linux中的进程状态转换

注:Linux下的TASK_RUNING状态包含了课本上的“运行”及“就绪”两种状体

通过ps命令,可以查看进程的状态:

R(TASK_RUNNING):可执行状态或运行状态

S(TASK_INTERRUPTIBLE):可中断阻塞状态,可响应中断、接收信号(如SIGKILL)

D( TASK_ UNINTERRUPTIBLE):不可中断阻塞状态,只能通过wake_up()函数明确唤醒时才能转换到可运行的就绪状态。

T( TASK_ STOPPED/ TASK_ TRACED):暂停状态或跟踪状态

Z( TASK_ DEAD/EXIT_ZOMBIE):退出状态,进程成为僵尸进程,此时,进程结束,但其父进程没有回收其剩余PCB资源,进程处于僵尸状态。

  • 内容1:练习编写以下实例,来分析和理解Linux中进程的状态转换

        a. 创建一个C程序,如run_status.c,运行一段长循环,使用gcc -o run_status run_status.c编译链接后,运行该程序;使用./run_status & ps ax | grep run_status命令查看程序状态,写出结果。

        b.使用kill命令,向run_status进程发送SIGSTOP信号,并使用ps命令观察其状态(进入了T状态),如:kill –SIGSTOP 进程号。

        c.创建一个C程序,如interruptiblie_status.c,让其睡眠30s

        d.编译链接,后台运行该程序(后接&),并使用ps命令查看运行状态;在该状态下,使用kill –SIGKILL 进程号可强行终止该进程,写出运行结果。

        e.创建一个C程序,如uninter_status.c,让其睡眠30s。使用kill -9 进程号命令后,用ps观察结果。说明:vfork也是进程创建函数,和fork函数的区别是:子进程创建后,父进程只能等到子进程调用exit或exec之后才能被调度执行;子进程和父进程共享空间。

        f.创建一个C程序,如zombie_status.c,在其中创建一个子进程,并让子进程迅速结束,而父进程陷入阻塞。

        g.编译链接,后台运行该程序,并使用ps命令查看运行状态(30s内)

3. 在Linux下,分析程序的功能与运行结果,熟悉Linux进程控制常用的系统调用。

(1)分析下列程序的功能与程序的运行结果。

#include <stdio.h>

main()

{   int p1,p2;

while((p1=fork())== -1);      

if (p1==0)

putchar('b');      

else

{   while((p2=fork( ))= = -1); 

if(p2==0)  putchar('c'); 

else  putchar('a');   

}

}

(2)分析使用wait()和exit()控制进程的程序功能与运行结果。

#include <stdio.h>

main()

{ int pid;

if(pid=fork())

{ wait();

printf("it is parent process\n");}

else

{ printf("it is child process\n");

exit();}   

printf("it is end\n");

}

(3) 写出下列程序的功能,并分析程序的运行结果。

#include <stdio.h>

main()

{   int p1,p2,i;

while((p1=fork())== -1);        

if (p1==0)

  for(i=0;i<10;i++)

printf("daughter %d\n",i);

else

{

                while((p2=fork())== -1); 

if(p2= =0)

                  for(i=0;i<10;i++)

                       printf("son %d\n",i);

else

                  for(i=0;i<10;i++)

                       printf("parent  %d\n",i);

}

}

(4)分析并完善下列程序。程序的功能是:输入两个整数并求和输出,然后创建一个子进程,当进程调度程序调度到父进程或子进程时将输出不同的信息。

#include <stdio.h>

main()

{ int i,j,k,sum;

scanf("%d%d",&j,&k);

sum=j+k;

printf("sum=%d \n",sum);

while(  (i=fork()) ==-1        )

{ printf("i=%d\n",i); }

if(  i=getpid()        )

printf("it is parent process!\n");

else

printf("it is child process!\n");

}

(5)分析并完善下列程序。程序的功能是:如果父进程要通过建立子进程在同一显示器上分别循环显示“Parents”和“Children”,循环次数由n决定。

#include <stdio.h>

main( )

{ int pid,n; n=1;

if((   fork()        )!=0)

While(n<10)

{ printf("%d",n++);

      printf("Parents"); }   

else

While(n<10)

{                  

       printf("Children"); }     

}

4. 线程异步并发实验

step1:编写一个c语言程序,初始化一个count变量为1;使用pthread_create函数创建两个线程,每个线程对count加1之后,显示“I am son, count=?”或“I am daughter, count=?”,?使用count值代替。父进程对count加之后,显示“I am father, count=?”,?使用count值替代。最后,父进程使用pthread_join等待两个线程结束后退出。

step2:编译后,运行该程序,分析屏幕上显示结果的顺序性,直至出现不一样的情况为止,观察每行打印结果中count的值。(注意,需要链接librt.so库,编译如:gcc -o tst_thread tst_thread.c -lrt)-lpthread -pthread

实验结果与分析

1.实例一

编写一个c程序run_status.c,如图3。

图3 创建c程序run_status.c

使用gcc -o run_status run_status.c编译链接,如图4。

图4 编译run_status.c

运行程序,使用./run_status & ps ax | grep run_status命令查看程序状态,如图5。

图5 运行程序后查看程序状态

结果分析:如图5所示,./run_status程序有一个pid为4465的进程处于T状态(暂停状态),该进程实际使CPU运行的时间为8s,pid为4480的进程状态为R状态(正在运行或在运行队列中等待)。

使run_status颜色高亮的进程pid为4482,处于S状态(休眠状态)。

2.实例二

使用kill命令,向run_status进程发送SIGSTOP信号,并使用ps命令观察其状态(进入了T状态),如图10,pid为4575的进程已进入T状态(暂停状态)。

图10使用kill命令向进程发送SIGSTOP信号

分析:观察到pid为4575的进程已进入T状态(暂停状态)。

3.实例三

使用kill命令,向run_status进程发送SIGCONT信号,并使用ps命令观察其状态(恢复到R状态),如图11,pid为4575的进程已进入R状态。

图11 使用kill命令向进程发送SIGCONT信号

4.实例四

创建一个c程序interruptible_statis.c,让其睡眠30s,如图12。

图12 创建c程序interruptible_statis.c

分析:该程序使终端休眠30秒。

5.实例五

图13 编译interruptible_statis.c 后台运行

图14 ps命令查看运行状态

图15 向后台运行的进程发送SIGKILL信号强行终止进程

分析:如图15,使用kill -SIGKILL 强行终止后台运行的./interruptible_status进程。观察到该进程killed(被杀死)。

6.实例六

创建一个C程序,uninter_status.c,如图16。

使用kill -9 进程号命令后,用ps观察结果,如图17。可观察到该进程被杀死。

图16 创建c程序uninter_status.c

图17 kill -9 进程号命令后,用ps观察结果

7.实例七

创建一个c语言程序,如zombie_status.c,在其中创建一个子进程,并让子进程迅速结束,而父进程陷入阻塞,如图18。

图18 创建c程序zombie_status.c

8.实例八

编译链接,后台运行程序zombie_status.c,并使用ps命令查看运行状态(30s内), 如图19。

图19 后台运行程序 ps查看运行状态图

分析状态:如图,可观察到pid为20552的程序为defunct状态。是一个早已死亡的僵尸进程。

9. 选做题

(1)

图20 选做题1代码文件

程序功能:程序创造子进程,根据fork返回的值输出不同字母,可判断当前进程是父进程还是子进程。当进程调度程序调度到父进程或子进程时将输出不同的信息

运行结果:

图21 选做题1运行结果

(2)

图22 选做题2代码文件

程序功能:如果fork返回0,在子进程中,fork返回新创建子进程的进程id,在父进程中。当进程调度程序调度到父进程或子进程时将输出不同的信息。

运行结果:

图23 选做题2运行结果

(3)

图24 选做题3代码文件

程序功能:创建两个进程,当进程调度程序调度到父进程或子进程时将输出不同的信息。

运行结果:

图25选做题3运行结果

(4)

图26 选做题4代码文件

程序功能:输入两个整数并求和输出,然后创建一个子进程,当进程调度程序调度到父进程或子进程时将输出不同的信息。

运行结果:

图27 选做题4运行结果

(5) 分析并完善下列程序。

图28 选做题5代码文件

程序功能:如果父进程要通过建立子进程在同一显示器上分别循环显示“Parents”和“Children”,循环次数由n决定。

运行结果:

图29 选做题5运行结果

10. 线程异步并发实验

编写一个c语言程序,如图

图30 test44.c

输入指令gcc test44.c -o test44 -lrt -pthread进行编译,如图

图31 编译test44.c

编译后运行该程序,如图

图32 运行teste44

如图所示,线程异步并发程序中,parent、son和daughter中的count不是独立的,先是在parent中count加1变为2,然后son中count又加1变为3,然后daughter中count又加1变为4。

总结

父进程和子进程二者并不共享地址空间,两个是单独的进程,继承以后二者不再有关联,子进程单独运行。同一进程中的所有线程共享所在进程的地址空间和全部资源,但线程间都相互独立的并发执行。

实验收获及体会

        本次实验中通过对于实验代码的编写,我巩固了使用Linux系统编辑、编译运行c语言程序,理解了进程的状态转换,了解了进程控制函数:fork、wait/waitpid函数,并且掌握了系统调用的简单编程。

        通过对实验代码运行结果的观察,我更加理解了进程控制的应用,深刻理解了进程的管理过程,在实验过程中也再一次巩固了我对于Linux系统常用指令的使用,这将为我今后操作系统的学习打下牢固的基础。

        实验结果往往能给我更加深刻的印象以及对课本理论知识更为深刻的理解,今后的理论知识学习过程中也应该注重动手实践。

实验 进程管理   Windows所创建的每个进程都从调用CreateProcess() API函数开始,该函数的任务是在对象管理器子系统内初始化进程对象。每一进程都以调用ExitProcess() 或TerminateProcess() API函数终止。通常应用程序的框架负责调用 ExitProcess() 函数。对于C++ 运行库来说,这一调用发生在应用程序的main() 函数返回之后。 1. 创建进程 CreateProcess() 调用的核心参数是可执行文件运行时的文件名及其命令行。表 2-1详细地列出了每个参数的类型和名称。   表2-1 CreateProcess() 函数的参数 参数名称 使用目的 LPCTSTR lpApplivationName 全部或部分地指明包括可执行代码的EXE文件的文件名 LPCTSTR lpCommandLine 向可执行文件发送的参数 LPSECURIITY_ATTRIBUTES lpProcessAttributes 返回进程句柄的安全属性。主要指明这一句柄是否应该由其他子进程所继承 LPSECURIITY_ATTRIBUTES lpThreadAttributes 返回进程的主线程的句柄的安全属性 BOOL bInheritHandle 一种标志,告诉系统允许新进程继承创建者进程的句柄 DWORD dwCreationFlage 特殊的创建标志 (如CREATE_SUSPENDED) 的位标记 LPVOID lpEnvironment 向新进程发送的一套环境变量;如为null值则发送调用者环境 LPCTSTR lpCurrentDirectory 新进程的启动目录 STARTUPINFO lpStartupInfo STARTUPINFO结构,包括新进程的输入和输出配置的详情 LPPROCESS_INFORMATION lpProcessInformation 调用的结果块;发送新应用程序的进程和主线程的句柄和ID   可以指定第一个参数,即应用程序的名称,其中包括相对于当前进程的当前目录的全路径或者利用搜索方法找到的路径;lpCommandLine参数允许调用者向新应用程序发送数据;接下来的三个参数与进程和它的主线程以及返回的指向该对象的句柄的安全性有关。 然后是标志参数,用以在dwCreationFlags参数中指明系统应该给予新进程什么行为。经常使用的标志是CREATE_SUSPNDED,告诉主线程立刻暂停。当准备好时,应该使用ResumeThread() API来启动进程。另一个常用的标志是CREATE_NEW_CONSOLE,告诉新进程启动自己的控制台窗口,而不是利用父窗口。这一参数还允许设置进程的优先级,用以向系统指明,相对于系统中所有其他的活动进程来说,给此进程多少CPU时间。 接着是CreateProcess() 函数调用所需要的三个通常使用缺省值的参数。第一个参数是lpEnvironment参数,指明为新进程提供的环境;第个参数是lpCurrentDirectory,可用于向主创进程发送与缺省目录不同的新进程使用的特殊的当前目录;第三个参数是STARTUPINFO数据结构所必需的,用于在必要时指明新应用程序的主窗口的外观。 CreateProcess() 的最后一个参数是用于新进程对象及其主线程的句柄和ID的返回值缓冲区。以PROCESS_INFORMATION结构中返回的句柄调用CloseHandle() API函数是重要的,因为如果不将这些句柄关闭的话,有可能危及主创进程终止之前的任何未释放的资源。 2. 正在运行的进程 如果一个进程拥有至少一个执行线程,则为正在系统中运行的进程。通常,这种进程使用主线程来指示它的存在。当主线程结束时,调用ExitProcess() API函数,通知系统终止它所拥有的所有正在运行、准备运行或正在挂起的其他线程。当进程正在运行时,可以查看它的许多特性,其中少数特性也允许加以修改。 首先可查看的进程特性是系统进程标识符 (PID) ,可利用GetCurrentProcessId() API函数来查看,与GetCurrentProcess() 相似,对该函数的调用不能失败,但返回的PID在整个系统中都可使用。其他的可显示当前进程信息的API函数还有GetStartupInfo()和GetProcessShutdownParameters() ,可给出进程存活期内的配置详情。 通常,一个进程需要它的运行期环境的信息。例如API函数GetModuleFileName() 和GetCommandLine() ,可以给出用在CreateProcess() 中的参数以启动应用程序。在创建应用程序时可使用的另一个
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值