进程的函数
创建进程:fork
fork()函数用于从已存在的一个进程中创建一个新的进程,新进程称为子进程,而原进程称为父进程。
要点 | 说明 |
---|---|
所需头文件 | #include <sys/types.h>/提供类型pid_t的定义/ #include <unistd.h> |
函数原型 | pid_t fork(void) |
函数返回值 | 0:子进程 子进程的pid:父进程 -1:出错 |
fork与vfork的区别
执行进程:exec簇函数
如果一个进程想执行另一个程序,那么它就可以调用 fork() 函数新建一个进程,然后调用 exec 函数族中的任意一个函数,这样看起来就像通过执行应用程序而产生了一个新进程
要点 | 说明 |
---|---|
所需头文件 | #include <unistd.h> |
函数原型 | 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 * file, char * const argv[],char * const envp[]); |
返回值 | -1:出错 |
从上面的表格中各个函数参数是不一样的:
l代表的是list:命令行参数列表
p代表的是path:搜索file时的使用的path变量
v代表的是vector:使用命令行参数数组
e代表的是environment:使用环境变量数组
这些参数必须以NULL结束
事实上,这6个函数中真正的系统调用只有execve(),其他5个都是库函数,它们最终都会调用execve()这个系统调用。在使用exec函数族时,一定要加上错误判断语句。exec 很容易执行失败,其中最常见的原因有:
① 找不到文件或路径,此时 errno 被设置为 ENOENT。
② 数组argv 和envp 忘记用NULL结束,此时,errno被设置为 EFAUL。
③ 没有对应可执行文件的运行权限,此时 errno 被设置为EACCES。
终止进程:exit()和_exit()函数
_exit()函数的作用是:直接使进程停止运行,清除其使用的内存空间,并清除其在内核中的各种数据结构;
exit()函数和_exit()函数的最大区别就在于exit()函数在终止当前进程之前要检查该进程打开过哪些文件,把文件缓冲区中的内容写回文件,也就是图1中的“清理I/O缓冲”一项。
在Linux的标准函数库中,有一种被称作“缓冲I/O(buffered I/O)”的操作,其特征就是对应每一个打开的文件,在内存中都有一片缓冲区。
每次读文件时,会连续读出若干条记录,这样在下次读文件时就可以直接从内存的缓冲区中读取;同样,每次写文件时,也仅仅是写入内存中的缓冲区,等满足了一定的条件(如达到一定数量或遇到特定字符等,最典型的就是咱们的vim中使用的:w命令),再将缓冲区中的内容一次性写入文件。
这种技术大大增加了文件读写的速度,但也给咱们的编程带来了一些麻烦。比如有些数据你认为已经被写入到文件中,实际上因为没有满足特定的条件,它们还只是被保存在缓冲区内,这时用_exit()函数直接将进程关闭掉,缓冲区中的数据就会丢失。因此,若想保证数据的完整性,最好使用exit()函数。
要点 | 说明 |
---|---|
所需头文件 | _exit():#include <unistd.h> exit():#include <stdlib.h> |
函数原型 | _exit():void _exit(int status) exit(): void exit(int status) |
参数说明 | status是一个整型参数,可以利用这个参数传递进程结束时的状态: ①0:进程正常结束。 ② 非0:表示进程出现错误。 在实际编程中,使用wait()来获取子进程的返回值。 |
wait()和waitpid()函数
1.wait()函数用于使父进程(也就是调用wait()的进程)阻塞,直到一个子进程结束或者该进程接收到了一个指定的信号为止。如果该父进程没有子进程或者它的子进程已经结束,则wait()就会立即返回。
2.waitpid()的作用和wait()一样,但它并不一定要等待第一个终止的子进程,它还有若干选项,如可提供一个非阻塞版本的wait()功能,也能支持作业控制。实际上,wait()函数只是waitpid()函数的一个特例,在Linux内部实现wait()函数时直接调用的就是waitpid()函数。
wait()函数语法要点
要点 | 说明 |
---|---|
所需头文件 | #include <sys/types.h> #include <sys/wait.h> |
函数原型 | pid_t wait(int *status) |
函数传入 | 这里的status是一个整型指针,是该子进程退出时的状态。若status不为空,则通过它可以获得子进程的结束状态。另外,子进程的结束状态可由Linux中一些特定的宏来测定 |
函数返回值 | 成功:已结束运行的子进程的进程号 失败:-1 |
waitpid()函数语法要点
要点 | 说明 |
---|---|
所需头文 | #include <sys/types.h> #include <sys/wait.h> |
函数原型 | pid_t waitpid(pid_t pid, int *status, int options) |
函数参数pid | pid > 0:只等待进程ID等于pid的子进程,不管是否已经有其他子进程运行结束退出,只要指定的子进程还没有结束,waitpid()就会一直等下去 pid = -1:等待任何一个子进程退出,此时和wait()作用一样 pid = 0:等待其组ID等于调用进程的组ID的任一子进程 pid < -1:等待其组ID等于pid的绝对值的任一子进程 |
函数参数status | 同wait() |
函数参数options | WNOHANG:若由pid指定的子进程没有结束,则waitpid()不阻塞而立即返回,此时返回值为0 WUNTRACED:为了实现某种操作,由pid指定的任一子进程已被暂停,且其状态自暂停以来还未报告过,则返回其状态 |
0:同wait(),阻塞父进程,等待子进程退出 |
|
函数返回 | 正常:已经结束运行的子进程的进程号 使用选项WNOHANG且没有子进程退出:0 调用出错:-1 |