进程与进程间通信(2)

1 创建进程

fork()函数来创建一个新进程,原型如下:

#include <unistd.h>
pid_t fork(void);

fork()函数将运行着的进程分裂出另一个子进程,它通过拷贝父进程的方式创建子进程。子进程与父进程有相同的代码空间、文件描述符等资源

 

fork()函数如果成功创建了进程,会对父子进程各返回一次,其中对父进程返回子进程的 PID,对子进程返回 0;失败返回小于 0 的错误码。

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
pid_t pid;
pid = fork(); /* 创建进程 */
if (pid == 0) { /* 对子进程返回 0 */
printf("Here is child, my pid = %d, parent's pid = %d\n", getpid(), getppid()); /* 打印父子进程 PID */
exit(0);
} else if(pid > 0) {       /*对父进程返回子进程 PID */
printf("Here is parent, my pid = %d, child's pid = %d\n", getpid(), pid);
} else {                       /* fork 出错 */

perror("fork error\n");
}
return 0;
}

2 终止进程:分为正常终止和异常终止两大类。

正常终止方式:

l 从 main()函数 return 返回;
l 调用类 exit()函数。

异常终止方式有:

l 调用 abort()函数;
l 接收到一个信号终止。

main()函数使用 return 指令返回时会自行调用类 exit()函数来终止进程。异常终止的abort()函数是通过 SIGABRT 信号来实现的。

通常在 Shell 中,可以使用$?变量来获取上次运行程序的退出状态。使用“echo $? ”命令获取程序退出状态,得到的值为 0,表示程序执行成功

3 exec 族函数

exec 族函数用来替换调用进程的执行程序。

 

调用 exec 族函数并不创建进程,因此前后进程的 ID 并无改变, exec 只是用一个全新的程序替换当前进程的执行程序。

exec 族函数有 6 个不同的 exec 函数,函数原型分别如下:
#include <unistd.h>
extern char **environ;
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 execvpe(const char *file, char *const argv[],char *const envp[]);

后缀 p:表示使用 filename 做参数,如果 filename 中包含“/”,则视为路径名,否则在 PATH 环境变量所指定的各个目录中搜索可执行文件,如 execlp()函数。无后缀 p 则使用路径名来指定可执行文件的位置,如 execl()函数。

后缀 e:表示可以传递一个指向环境字符串指针数组的指针,环境数组需要以 NULL 结束,如 execvpe()函数。而无此后缀的函数则使用调用进程中 environ 变量为新程序复制现有的环境,如 execv()函数。

后缀 l: 表示使用 list 形式来传递新程序的参数,传给新程序的所有参数以可变参数的形式从 exec 给出,最后一个参数需要为 NULL 以表示结束,如 execl()函数。

后缀 v: 表示使用 vector 形式来传递新程序的参数,传给新程序的所有参数放入一个字符串数组中,数组以 NULL 结束以表示结束,如 execv()函数。

exec 族函数只有在出错的时候才会返回,如果成功,该函数无返回,否则返回-1。

4 wait()函数

wait()函数用来帮助父进程获取其子进程的退出状态。当进程退出时,内核为每一个进程保存了一定量的退出状态信息,父进程可根据此退出信息来判断子进程的运行状况。如果父进程未调用 wait()函数,则子进程的退出信息将一直保存在内存中。

l 僵尸进程:如果子进程先终止,但其父进程未为其调用 wait()函数,那么该子进程就变为僵尸进程。僵尸进程在它父进程为它调用 wait()函数之前将一直占有系统的
内存资源。

l 孤儿进程:如果父进程先终止,尚未终止的子进程将会变成孤儿进程。孤儿进程将直接被 init 进程收管,由 init 进程负责收集它们的退出状态。

wait()函数原型

include <sys/types.h>

#include <sys/wait.h>

pid_t wait(int *status);

参数 status 是一个用来保存子进程退出状态的指针,函数成功则返回获取到退出状态进程的 PID,否则返回-1。

 

5 守护进程

    守护进程(Daemon) 是运行在后台的一种特殊进程。它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件,它不需要用户输入就能运行并提供某种服务。守护进程的父进程是 init 进程,因为它真正的父进程在 fork 出子进程后就先于子进程exit 退出了,所以它是一个由 init 继承的孤儿进程。

daemon()函数的原型

#include <unistd.h>

int daemon(int nochdir, int noclose);

参数 nochdir:如果传入 0,则 daemon 函数将调用进程的工作目录设置为根目录,

否则保持原有的工作目录不变;

参数 noclose:如果传入 0,则 daemon 函数将重定向标准输入、标准输出、标准错误输出到/dev/null 文件中,否则不改变这些文件描述符。

该函数如果成功则返回 0,否则返回-1,并设置 errno。

猜你喜欢

转载自www.cnblogs.com/xiaoli94/p/11235704.html