三、Linux--进程

1 fork()

头文件

#include<unistd.h>/*#包含<unistd.h>*/

#include<sys/types.h>/*#包含<sys/types.h>*/

函数原型

pid_t fork( void);

pid_t 是一个宏定义,其实质是int 被定义在#include<sys/types.h>中)

返回值 若成功调用一次则返回两个值,子进程返回0,父进程返回子进程ID;否则,出错返回-1

函数说明

 

一个现有进程可以调用fork函数创建一个新进程。由fork创建的新进程被称为子进程(child process)。fork函数被调用一次但返回两次。两次返回的唯一区别是子进程中返回0值而父进程中返回子进程ID

子进程是父进程的副本,它将获得父进程数据空间、堆、栈等资源的副本。注意,子进程持有的是上述存储空间的“副本”,这意味着父子进程间不共享这些存储空间。

UNIX将复制父进程的地址空间内容给子进程,因此,子进程有了独立的地址空间。在不同的UNIX (Like)系统下,我们无法确定fork之后是子进程先运行还是父进程先运行,这依赖于系统的实现。所以在移植代码的时候我们不应该对此作出任何的假设。

为什么fork会返回两次?

由于在复制时复制了父进程的堆栈段,所以两个进程都停留在fork函数中,等待返回。因此fork函数会返回两次,一次是在父进程中返回,另一次是在子进程中返回,这两次的返回值是不一样的。过程如下图

本地图片,请重新上传 

 

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

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

在子进程中,fork返回0

如果出现错误,fork返回一个负值。

fork函数执行完毕后,如果创建新进程成功,则出现两个进程,一个是子进程,一个是父进程。在子进程中,fork函数返回0,在父进程中,fork返回新创建子进程的进程ID。我们可以通过fork返回的值来判断当前进程是子进程还是父进程。

引用一位网友的话来解释fork函数返回的值为什么在父子进程中不同。“其实就相当于链表,进程形成了链表,父进程的fork函数返回的值指向子进程的进程id, 因为子进程没有子进程,所以其fork函数返回的值为0.

调用fork之后,数据、堆、栈有两份,代码仍然为一份但是这个代码段成为两个进程的共享代码段都从fork函数中返回,箭头表示各自的执行处。当父子进程有一个想要修改数据或者堆栈时,两个进程真正分裂。

2 getpid();

getpid函数原型为: pid_t getpid(void);

函数返回值为当前进程的PID

3 getppid();

getppid函数原型为: pid_t getppid(void);

函数返回当前进程的父进程PID.

 

4 execl()

头文件

#include <unistd.h>

函数定义

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

函数返回值

成功则不返回值, 失败返回-1, 失败原因存于errno中,可通过perror()打印

函数说明

execl()其中后缀"l"代表list也就是参数列表的意思,第一参数path字符指针所指向要执行的文件路径, 接下来的参数代表执行该文件时传递的参数列表:argv[0],argv[1]... 最后一个参数须用空指针NULL作结束。

Fork函数创建一个子进程后往往要调用exec函数以执行另一个程序。当进程调用execl函数时,该进程执行的程序完全替换为新程序,新程序则从其main函数开始执行。因为调用exec函数并不是创建新进程,所以前后的进程ID并没有改变。Exec只是用磁盘上的新程序替换了当前进程的正文段、数据段、堆段和栈段。

 

例:

/* 执行 /home/xjf/fil/shownum*/

#include <unistd.h>        

main()

{

// 执行/home/xjf/fil/目录下的shownum, 第一参数为程序名showname, 第二个参数 12

execl("/home/xjf/fil/shownum", "shownum", "12", NULL);

}

5 wait()

#include <sys/types.h>

#include <sys/wait.h>

pid_t wait(int *status)

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

参数status用来保存被收集进程退出时的一些状态,它是一个指向int类型的指针。但如果我们对这个子进程是如何死掉的毫不在意,只想把这个僵尸进程消灭掉,(事实上绝大多数情况下,我们都会这样想),我们就可以设定这个参数为NULL,就象下面这样:

 pid = wait(NULL);

返回值

如果成功,wait会返回被收集的子进程的进程ID,如果调用进程没有子进程,调用就会失败,此时wait返回-1,同时errno被置为ECHILD

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值