多进程相关系统调用

1、fork函数
#include<sys/types.h>
#include<unistd.h>
pid_t fork(void);
  • 函数每次调用都返回两次,在父进程中返回子进程ID,在子进程中返回0。调用失败是返回-1,并置errno。
  • fork函数复制当前进程,在内核进程表中创建一个新的进程表项,新进程很多属性与原进程相同,例如堆栈指针,标志寄存器等,也有属性不同,例如PID,PPID,信号位图(原进程设置的信号处理函数不再对新进程起作用)。
  • 写时复制
  • 父进程中打开的文件描述符,在子进程中也是打开的,且文件描述符的引用计数加1

2、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 execve(const char* path, char* const argv[], char* const envp[]);

  • exec函数功能是替换进程映像
  • path参数指定可执行文件的完整路径
  • file参数可以接受文件名,文件的具体位置则在环境变量PATH中搜索
  • arg接收可变参数,argv接收参数数组,它们都会被传递给新的程序的main函数
  • envp参数用于设置新程序的环境变量,如果未设置,则使用全局变量environ指定的环境变量
  • exec函数一般不返回,出错才返回-1,并设置errno。如果没有出错,exec函数之后的代码不会执行

3、wait和waitpid函数

    在多进程中,父进程一般是要跟踪子进程的退出状态的,所以,在子进程运行结束时,内核并不会立即释放该进程的进程表表项,而是要等待父进程对该子进程退出信息的查询后才释放。

    僵尸进程有两种情况,其一,子进程结束运行,而父进程还没有读取其退出状态之前,此期间子进程处于僵尸状态。其二,父进程先结束运行,而子进程继续运行,此时子进程将由init进程接管,则父进程退出之后,子进程退出之前,子进程处于僵尸状态。僵尸状态的进程会占据着内核资源。wait和waitpid函数就是用来避免僵尸进程的产生的,在父进程中调用,以等待子进程退出,并获取退出信息。

#include<sys/types.h>
#include<sys/wait.h>
pid_t wait(int* stat_loc);
pid_t waitpid(pid_t pid, int* stat_lic, int options)
  • wait函数将阻塞进程,直到某个子进程结束为止,返回子进程的pid,并将退出状态信息存储于stat_loc参数指向的内存中。
  • waitpid函数只等待有pid参数指定的子进程,如果pid为-1,则等待任一子进程退出。options参数取值为WNOHANG可控制函数为非阻塞的,此时pid指定的子进程如果没有结束或意外终止,则立即返回0,如果子进程正常退出,则返回该子进程的PID。waitpid函数调用失败返回-1,并设置errno。

    对于非阻塞的调用,在事件已经发生时再执行,效率才会更高,所以对于waitpid函数,应该在某个子进程已经退出了,再调用它。SIGCHLD信号则是在一个进程退出时发送给其父进程的信号,所以可以在父进程中捕获SIGCHLD信号,并在信号处理函数中调用waitpid函数。


猜你喜欢

转载自blog.csdn.net/fangyan5218/article/details/80346312