Linux——进程(下)

打印 上一主题 下一主题

主题 799|帖子 799|积分 2397

一.进程创建

   进程调用  fork  ,当控制转移到内核中的  fork  代码后,内核做:   

  • 分配新的内存块和内核数据结构给子进程
  • 将父进程部分数据结构内容拷贝至子进程
  • 添加子进程到体系进程列表当中
  • fork返回,开始调度器调度

二.进程停止

1.为什么停止

释放曾经的代码和数据所占据的空间。释放内核数据结构。

2.停止的三种情况



  • 代码跑完,结果正确
  • 代码跑完,结果不正确
  • 代码实行时,出现了异常,提前退出了。
echo $?指令:父进程bash获取到迩来一个的子进程的退出码,要知道子进程的退出情况。
结果是否正确可以通过进程的退出码决定,退出码为0表现退出成功,非0则表现失败
非0的情况有多种,每个退出码都代表失败的不同原因,可以使用下述函数,通过退出码来打印退出信息:
   char *strerror(int errnum); 
  父进程bash要通过退出码来获取子进程的退出情况(成功或失败,失败的原因),为用户负责。 
进程的异常退出,本质是进程收到了OS发出的进程信号
想知道进程如何异常退出,可以看进程退出时的退出信号是多少
衡量一个进程退出的情况,只需要两个数字,退出码和退出信号

3.如何停止



  • main函数中直接return,表现进程停止(非main函数,return表现函数竣事,而非进程退出)。
  • 代码调用exit函数。在代码的恣意位置调用exit,都代表进程停止。
  • _exit() -- 体系指令。
exit和_exit的区别:exit会在进程退出时冲刷缓冲区,_exit不会。

三.进程等候

1.为什么等候

任何子进程,在退出情况下,一般必须要被父进程举行等候。等候的原因如下:


  • 父进程通过等候,解决子进程退出的僵尸题目,回收体系资源(必须考虑)。
  • 获取子进程的退出信息,知道子进程是因为什么原因退出的(非必须)。

2.怎么等候

函数



  • pid_t wait(int *status):等候父进程中,恣意一个子进程退出,等候成功返回子进程的pid。
  • pid_t waitpid(pid_t pid,int *status,int options)
在子进程退出之前,父进程会不停举行阻塞等候,而不会实行自己的代码。 

参数

pid:


  • pid = -1 ,表现等候任一个子进程,与wait等效。
  • pid>0,等候其进程ID与输入的pid相称的子进程。
status:
输出型参数,用于得到子进程的退出信息。退出信息包括:退出码和退出信号
如果父进程不关心子进程的退出信息,则可以设为NULL。 
int范例的status由32位构成,此中高16位不使用,对于低16位,高8位为进程的退出码,低七位为进程的退出信号。 



  • WIFEXITED(status)函数:若为正常停止子进程返回的状态,则为真。(查察进程是否正常退出)
  • WEXITSTATUS(status)函数:若WIFEXITED函数返回值非零,提取子进程退出码。(查察进程退出码)
options:
子进程没有退出,而父进程在实行waitpid等候子进程,就会导致阻塞等候,即options默认为0。
将options改为WNOHANG,则为非阻塞等候
阻塞等候下,父进程调用waitpid函数会不停等候子进程的状态,直到其达到某种情况(如退出)才会停止等候
非阻塞等候下,父进程调用waitpid函数只会确认一次子进程的状态,而不举行等候,可以干其他事。此时,父进程需要循环调用waitpid函数来判断子进程是否退出,
非阻塞等候 + 循环 = 非阻塞轮询 

返回值

阻塞等候:


  • 当正常返回的时候,waitpid返回网络到的子进程的进程ID;
  • 如果调用中堕落,则返回-1,这时erron会被设置成相应的值以示错误所在。
非阻塞等候:


  • pid_t > 0:等候成功的,子进程退出了,并且父进程回收成功。
  • pid_t < 0:等候失败了。
  • pid_t == 0:检测是成功了,只不过子进程还没完全退出,需要你下一次举行重复等候。

四.进程替换

使用exec*系列的函数在原本的程序中实行新的程序,称为程序替换。 
其本质是exec*系列的函数雷同于linux体系上的加载函数将新的程序加载到内存中
exec*系列的函数,实行完之后,后边的代码不会再被实行,因为被替换了。
这些函数的返回值不消关心只要替换成功,就不会向后运行,如果向后运行,代表替换失败
进程 = 内核数据结构 + 代码和数据,而进程替换即替换掉代码和数据,没有创建新的进程,而是复用原本的假造地址空间和页表,重新创建页表映射关系
当父进程创建子进程,通过进程替换让子进程去实行一个新的进程时,父进程的代码和数据都将举行写时拷贝,子进程将享有新的代码和数据,实现与父进程的完全独立

1.替换函数

exec*是整个替换函数系列的开头,后边追加的字符则代表不同的含义

(1)execl         

   int execl(const char *path,const char *arg,...)
  

  • “l”代表list,即列表,表现该函数可以按列表方式实行程序。
  • path是程序所在的路径,实行程序必须要给出其所在的路径。
  • arg表现程序名(指令名)。
  • "..."表现该函数为变参函数,用于追加多个后缀指令。
  • 参数必须以NULL末端。
例子:
   execl("/usr/bin/ls","ls","-l","-a",NULL);
  ls -l -a即为一个列表
  实行ls -l -a指令。

(2)execv

   int execv(const char *path, char *const argv[])
  

  • "v"表现数组vector,阐明该函数调用的指令需要从数组中获取。
  • argv即为要存放指令的数组。
例子:
   char *const argv[] = ("ls","-l","-a",NULL);
  execv("/usr/bin/ls",argv);
  
 execlp/execvp

   int execlp(const char *flie,const char *arg,...)
  int execvp(const char *file, char *const argv[])
  "p"表现情况变量PATH。
这两个函数与上述两种函数功能完全相同,但是使用这两个函数,第一个参数可以不传要实行的程序所在的路径,而只需传入该程序的名字,而后函数会从体系的PATH情况变量下找到该程序并实行

execle/execvpe

   int execle(const char *flie,const char *arg,...,char *const envp[])
  int execvpe(const char *file, char *const argv[],char *const envp[])
  e表现情况变量,使用这两种函数,用户替换程序的情况变量
本质是用新的情况变量替换程序原本的情况变量, 使其成为新情况变量下的程序

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

冬雨财经

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表