南邮操作系统——实验二——进程控制

实验要求:

学习和了解进程控制的基本和常用的系统调用 fork wait sleep exit exec 等等。

查看 /usr/src/include/sched.h中的task_struct 数据结构,并分析Linux 操作系统进程状态。

通过进程创建的应用实例,深刻理解进程创建的过程。

思考题:

1、当首次调用新创建进程时,其入口在哪里?

2、可执行文件加载时进行了哪些处理?

3、什么是进程同步?wait( )是如何实现进程同步的?

实验一

1、修改源程序

如果按实验指导代码运行你,你会发现报错:

file.c:23:1: note: include ‘<stdlib.h>’ or provide a declaration of ‘exit’
因此需要填上头文件 include <stdlib.h>

2、正确的代码如下

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>  //实验指导上少了这一个头文件
int main(void)
{
pid_t pid;
int data=5;
if((pid=fork())<0)
{
printf("fork error\n");
exit(0);
}
else if(pid==0)
{
data--;
printf("child\'s data is:%d\n",data);
exit(0);
}
else
{
printf("parent\'s data is:%d\n",data);
}
exit(0);
}

3、运行的流程

详见我上一篇博文,使用vi运行c文件

4、fork()函数函数注明

为什么明明是if-else,却输出两个结果

这是因为

fork()函数
1、在Linux中从已存在的进程中创建一个新的进程唯一方法是使用fork()或vfork(),,原来存在的进程为父进程,新创建的进程为子进程,fork()函数执行一次返回两个值,子进程返回0,父进程返回子进程的PID,出错返回-1;使用fork()创建的子进程就是父进程的一个复制品,子进程继承了整个进程的地址空间,包括进程上下文、进程堆栈、内存信息、打开的文件描述符、信号控制设定、进程优先级、进程组号、当前工作目录、根目录、资源限制、控制终端等,而子进程所独有的只有它的进程号、资源使用和计时器等。

2、使用fork()创建子进程后,在程序运行时,子进程和父进程同时运行,同时!而,fork()函数执行一次返回两个值,子进程返回0,父进程返回子进程的PID,出错返回-1;因此子进程运行时pid=0,输出“child”,父进程时,pid>0,输出“parent”

3、程序流程:

4、Linux pid_t 类型的定义,具体可以查考这篇博文,结论即,pid_t就是int。

实验二

1、修改源程序及wait()函数说明

按实验指导运行,报错

故修改如下

1、由于使用wait()函数需要头文件

#include <sys/types.h>/* 提供类型pid_t的定义*/

#include <sys/wait.h>

故添加#include <sys/wait.h>

2、wait()函数功能是:
父进程一旦调用了wait就立即阻塞自己,由wait自动分析是否当前进程的某个子进程已经退出,如果让它找到了这样一个已经变成僵尸的子进程,wait就会收集这个子进程的信息,并把它彻底销毁后返回;如果没有找到这样一个子进程,wait就会一直阻塞在这里,直到有一个出现为止。

原型int wait(int *status)

参数status用来保存被收集进程退出时的一些状态,它是一个指向int类型的指针。但如果我们对这个子进程是如何死掉毫不在意,只想把这个僵尸进程消灭掉,(事实上绝大多数情况下,我们都会这样想),我们就可以设定这个参数为NULL,就像下面这样:
pid = wait(NULL);
如果成功,wait会返回被收集的子进程的进程ID,如果调用进程没有子进程,调用就会失败,此时wait返回-1,同时errno被置为ECHILD。

故将wait()修改为pid = wait(NULL);

2、正确代码

#include <stdio.h> 
#include <sys/types.h> 
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>   //实验指导上少了这一个头文件"#include <sys/wait.h>  //实验指导上少了这一个头文件
void main( ) 
{ 
  pid_t pid; 

  char *path="/bin/ps"; 
  char *argv[5]={ "ps","-a","-x",NULL}; 
printf("Run ps with execve by child process:\n"); 
  if((pid=fork( ))<0) 
{ 
printf("fork error!"); 
  exit(0); 
} 
else if (pid==0) 
{ 
  if(execve(path,argv,0)<0) 
   { 
     printf("fork error!"); 
     exit(0); 
   } 
printf("child is ok!\n"); 
exit(0); 
} 
//wait( ); 
pid = wait(NULL);  //实验指导上 wait 用错了
printf("it is ok!\n"); 
exit(0); 
} 

3、运行过程及结果

4、函数注明:exec函数族及exit()/_exit()

1、exec函数族
exec函数主要用于在进程中启动另一个程序执行的方法,exec函数族是6个以exec字母开头的函数,这6个函数执行成功不返回,只有出错时返回-1,它们就是:

int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg, ..., char *const 
envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execve(const char *

下面对这些函数参数进行说明: 
(1)通过对比这些函数,发现只有函数名的第五和第六位的字母不一样,首先看不带字母“p”的函数,第一个参数必须是可执行程序的绝对路径或相对路径,而不能是文件名,这个路径就是PATH环境变量的值; 
(2)带有字母“l ”(表示list )的exec函数要求将新程序的每个命令行参数都当作一个参数传给它,命令行参数的个数是可变的,因此函数原型中有… ,… 中的最后一个可变参数应该是NULL,起sentinel的作用; 
(3)带有字母“v”(表示vector )的函数,则应该先构造一个指向各参数的指针数组,然后将该数组的首地址当作参数传给它,数组中的最后一个指针也应该是NULL,就像main函数的argv参数或者环境变量表一样; 
(4)以“e” (表示environment )结尾的exec函数,可以把一份新的环境变量表传给它,其他exec函数仍使用当前的环境变量表执行新程序。 

简而言之,该函数就是用指定程序覆盖当前程序代码,启动另一个程序。因此本文中由其调用execve启动shell命令ps查看系统当前的进程信息。

2、exit()/_exit()

exit()和_exit()都是用来无条件中止进程,在调用exit()比exit()时多做了些清理、保存工作,最后执行exit()中止进程执行;而_exit()则是直接执行exit()中止进程执行。对于由exit()结束的函数无论你函数原型是void 或者int都可以运行

思考题

1、当首次调用新创建进程时,其入口在哪里?

答:

程序流程:

2、可执行文件加载时进行了哪些处理?

将源代码转换为机器可认识代码的过程。编译程序读取源程序(字符流),对之进行词法

和语法的分析,将高级语言指令转换为功能等效的汇编代码,再由汇编程序转换为机器语言,

并且按照操作系统对可执行文件格式的要求链接生成可执行程序。具体经过以下几个处理:

C源程序一>编译预处理一>编译一>优化程序一>汇编程序一>链接程序一>可执行文件

3、什么是进程同步?wait( )是如何实现进程同步的?

进程同步是指对多个相关进程在执行次序上进行协调,以使并发执行的主进程之间有

效地共享资源和相互合作,从而使程序的执行具有可在现行。

首先,程序在调用fork()机那里了一个子进程后,马上调用wait(),使父进程在子进程调

用之前一直处于睡眠状态,这样就使子进程先运行,子进程运行exec()装入命令后,然后调用wait(0),使子进程和父进程并发执行,实现进程同步。

参考链接:

https://blog.csdn.net/wuqishuang/article/details/48399251

https://www.cnblogs.com/kazama/p/10734951.html

https://bbs.csdn.net/topics/350133461

https://www.cnblogs.com/kazama/p/10734962.html

https://blog.csdn.net/k346k346/article/details/80212265

https://blog.csdn.net/vict_wang/article/details/88546963

  • 6
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值