目录
头文件
#include <unistd.h>:fork
函数
#include <stdlib.h>:exit
函数
#include <sys/types.h>包含了一些系统定义的数据类型,如 pid_t
(用于表示进程ID)和其他进程相关的数据类型。
#include <sys/wait.h>包含了一些用于等待子进程状态的函数和宏定义,最常用的函数是 waitpid()
,它用于等待指定的子进程终止并获取其状态信息。此外,还有一些宏定义,如 WIFEXITED
、WIFSIGNALED
、WEXITSTATUS
等,用于检查子进程的终止状态。
一、概述
在Linux系统中,进程控制是指通过系统调用和相关函数来创建、管理和终止进程的过程。以下是一些常用的进程控制相关的系统调用和函数:
-
fork():用于创建一个新的子进程,使得父进程和子进程都从调用fork()的位置开始执行,但是在父子进程中返回的值不同。返回值为0表示当前进程为子进程,返回值大于0表示当前进程为父进程,返回值为-1表示创建子进程失败。
-
exec():用于在当前进程中执行新的程序。exec()函数族包括execve()、execvp()、execl()等,它们用于不同的执行方式和参数传递方式。
-
wait():用于父进程等待子进程的结束。父进程调用wait()会阻塞,直到一个子进程结束或者收到一个信号。wait()函数返回结束子进程的进程ID。
-
waitpid():用于父进程指定等待某个特定的子进程。可以指定等待某个特定进程ID的子进程,也可以使用一些选项来控制等待的行为。
-
exit():用于进程的正常终止。通过exit()函数可以终止当前进程,并返回一个退出状态给父进程。
-
kill():用于向指定进程发送信号。可以通过kill()函数向进程发送不同的信号,如终止进程、停止进程、重新启动进程等。
-
signal():用于设置信号处理函数。通过signal()函数可以设置对某个特定信号的处理方式,如忽略、捕捉并处理等。
-
getpid():获取当前进程的进程ID。
-
getppid():获取当前进程的父进程ID。
这些是一些常用的进程控制相关的系统调用和函数,可以通过它们来实现进程的创建、管理和终止。在实际应用中,还有其他更高级的进程控制机制和函数,如进程间通信(IPC)、线程控制等,用于更复杂的进程管理和同步操作。
执行顺序
二、用法操作
a、execvp
execvp(args[0], args)
是一个函数调用,用于在当前进程中执行指定的程序文件。
execvp
是一个系统调用,其原型为int execvp(const char *file, char *const argv[])
,位于<unistd.h>
头文件中。args[0]
是要执行的程序文件的路径,通常是一个字符串。args
是一个字符串数组,用于传递命令行参数给要执行的程序。
execvp
函数会搜索与 file
参数指定的程序文件名匹配的可执行文件,并用该可执行文件替换当前进程的内容。在执行成功后,当前进程就成为了新程序的进程。
这个函数的特点是可以直接使用命令名和命令行参数来执行程序,无需指定可执行文件的完整路径。它会在系统的 PATH
环境变量指定的路径中搜索可执行文件。
execvp
函数会取代当前进程的代码和数据,并且不会返回,除非发生错误。如果 execvp
调用成功,那么当前进程将会运行新程序的代码,并以新程序的形式继续执行。如果发生错误,execvp
函数将返回 -1,并设置相应的错误码,表示执行失败。
请注意,execvp
函数会终止当前进程的执行,因此后续的代码将不会执行。如果需要在执行 execvp
后进行其他操作,可以在 execvp
调用之前使用 fork
创建一个子进程,然后在子进程中调用 execvp
,这样父进程仍然可以继续执行其他操作。
b、waitpid
waitpid是一个用于等待子进程结束的系统调用函数。
函数原型为:pid_t waitpid(pid_t pid, int *status, int options);
,头文件为<sys/wait.h>
。
pid
参数指定要等待的子进程的进程ID。可以有以下取值:> 0
:等待具有指定进程ID的子进程。-1
:等待任意子进程。0
:等待与当前进程在同一进程组的任意子进程。< -1
:等待指定进程组ID的任意子进程。
status
参数是一个整型指针,用于获取子进程的退出状态。如果不关心子进程的退出状态,可以将该参数设置为NULL
。options
参数是一个整数,用于指定等待子进程的行为选项,可以是以下常量的按位或组合:WNOHANG
:非阻塞模式,即不阻塞等待子进程结束,如果没有子进程结束,则立即返回。WUNTRACED
:追踪被停止的子进程的状态。WCONTINUED
:追踪被继续执行的被暂停的子进程的状态。- 其他选项,如
WSTOPPED
、WEXITED
等,用于指定等待子进程的具体状态。
waitpid
函数的返回值有以下几种情况:
-1
:表示等待出错,具体错误信息可以通过errno
来获取。0
:表示在非阻塞模式下,没有已结束的子进程,即子进程仍在运行。> 0
:表示等待的子进程的进程ID,即成功等待到了指定的子进程结束。
注意:waitpid
函数是一个阻塞函数,会使当前进程进入阻塞状态,直到等待的子进程结束或满足其他条件才返回。如果没有满足条件的子进程,父进程将一直阻塞。
实例
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int main() {
pid_t pid = fork();
if (pid == -1) {
perror("fork");
return 1;
} else if (pid == 0) {
// 子进程代码
printf("Child process: Hello\n");
sleep(2);
printf("Child process: Exiting\n");
return 0;
} else {
// 父进程代码
printf("Parent process: Waiting for child to exit...\n");
int status;//定义一个变量没有初始化,那就是NULL
pid_t child_pid = waitpid(pid, &status, 0);
if (child_pid == -1) {
perror("waitpid");
return 1;
}
if (WIFEXITED(status)) {
printf("Parent process: Child exited with status %d\n", WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
printf("Parent process: Child terminated by signal %d\n", WTERMSIG(status));
} else if (WIFSTOPPED(status)) {
printf("Parent process: Child stopped by signal %d\n", WSTOPSIG(status));
} else if (WIFCONTINUED(status)) {
printf("Parent process: Child continued\n");
}
printf("Parent process: Done\n");
return 0;
}
}
在waitpid
函数中,第三个参数options
用于指定额外的选项来控制等待子进程的行为。当options
的值为0时,表示不设置任何选项,即以默认方式等待子进程的结束。
默认方式下,waitpid
函数会阻塞父进程,直到指定的子进程结束。如果子进程已经结束,则立即返回。当子进程结束后,父进程可以通过status
参数获取子进程的退出状态信息。
需要注意的是,当options
为0时,waitpid
函数是一个阻塞调用,即父进程会一直等待子进程结束,直到子进程退出或被信号中断。如果不希望父进程阻塞,可以使用其他选项来改变等待行为,例如设置WNOHANG
选项,使得waitpid
在没有子进程结束时立即返回。具体的选项可以参考相关的系统文档或手册页。
wait(NULL)
c、exit()
在C语言中,exit()
是一个库函数,用于终止程序的执行并返回到操作系统。它接受一个整数参数作为退出状态码,并且没有返回值。
exit()
函数的作用是正常终止程序的执行,并将退出状态码传递给操作系统。退出状态码是一个整数值,通常用于指示程序的执行结果或状态。一般约定,返回值为0表示程序执行成功,非零值表示程序执行失败或出现错误。
当调用exit()
函数时,程序会立即停止执行并返回到操作系统。它会执行一些清理操作,例如关闭打开的文件、释放分配的内存等。然后,操作系统会接管程序的控制权,并根据传递的退出状态码来处理程序的结束情况。
三、信号处理
a、signal
b、SIGQUIT
c、SIGALRM