进程管理2

本文介绍了进程管理中的exec,wait,waitpid系统调用,详细讲解了它们的使用方法和作用。exec系列函数用于执行新程序,wait和waitpid用于回收子进程资源,避免产生僵尸进程。通过正确使用这些调用,可以有效地管理进程状态,防止僵尸进程的出现。" 113549772,10549185,解决SQL Server 2008 R2远程连接失败的问题,"['SQL Server', '数据库管理', '远程连接', '系统配置']

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

进程管理2

exec,wait,waitpid系统调用

exec
包含头文件<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[]);
path参数表示你要启动程序的名称包括路径名
arg参数表示启动程序所带的参数
返回值:成功返回0,失败返回-1

不带字母 p的exec函数第一个参数必须是程序的相对路径或绝对路径
带有字母l(表示list)的exec函数要求将新程序的每个命令行参数都当作一个参数传
给它,命令行参数的个数是可变的,最后一个可变参数应该是
NULL
对于带有字母v(表示vector)的函数,则应该先构造一个指向
各参数的指针数组,然后将该数组的首地址当作参数传给它,数组中的最后一个指针也应该
是NULL,就像main函数的argv参数或者环境变量表一样
对于以e(表示environment)结尾的exec函数,可以把一份新的环境变量表传给它,其
他exec函数仍使用当前的环境变量表执行新程序
举例

char *const ps_argv[] ={"ps", "-o", "pid,ppid,pgrp,session,tpgid,comm", NULL};
char *const ps_envp[] ={"PATH=/bin:/usr/bin", "TERM=console", NULL};
execl("/bin/ps", "ps", "-o", "pid,ppid,pgrp,session,tpgid,comm", NULL);
execv("/bin/ps", ps_argv);
execle("/bin/ps", "ps", "-o", "pid,ppid,pgrp,session,tpgid,comm", NULL, ps_envp);
execve("/bin/ps", ps_argv, ps_envp);
execlp("ps", "ps", "-o", "pid,ppid,pgrp,session,tpgid,comm", NULL);
execvp("ps", ps_argv);

#include <unistd.h>
#include <stdlib.h>
int main(void)
{
execlp("ps", "ps", "-o", "pid,ppid,pgrp,session,tpgid,comm", NULL);
perror("exec ps");
exit(1);
}

事实上,只有execve是真正的系统调用,其它五个函数最终都调用execve
调用exec后,原来打开的文件描述符仍然是打开的。利用这一点可以实现I/O重定向。

由于exec函数只有错误返回值,只要返回了一定是出错了,所以不需要判断它的
返回值,直接在后面调用perror即可

wait/waitpid
函数原型
pid_t wait(int *status);
pid_t waitpid(pid_t pid, int *status, int options);

僵尸进程: 子进程退出,父进程没有回收子进程资源(PCB),则子进程变成僵尸进程
孤儿进程: 父进程先于子进程结束,则子进程成为孤儿进程,子进程的父进程成为1号
进程init进程,称为init进程领养孤儿进程
wait/waitpid的作用
一个进程在终止时会关闭所有文件描述符,释放在用户空间分配的内存,但它的PCB还
保留着,内核在其中保存了一些信息:如果是正常终止则保存着退出状态,如果是异常终止
则保存着导致该进程终止的信号是哪个。这个进程的父进程可以调用wait或waitpid获取这
些信息,然后彻底清除掉这个进程。
其实进程在刚终止时都是僵尸进程,正常情况下,僵尸进程都立刻被父进程清理了,但是如果没有立即被清理,应调用wait/waitpid清理
例子

#include <unistd.h>
#include <stdlib.h>
int main(void)
{
pid_t pid=fork();
if(pid<0) {
perror("fork");
exit(1);
}
if(pid>0) { /* parent */
while(1);
}
/* child */
return 0;
}

父进程进入循环,子进程已经完成任务,未结束,变为僵尸进程。应调用wait/waitpid清除
若调用成功则返回清理掉的子进程 id,若调用出错则返回-1。父进程调用 wait或
waitpid时可能会:

  • 阻塞(如果它的所有子进程都还在运行)。

  • 带子进程的终止信息立即返回(如果一个子进程已终止,正等待父进程读取其终止信
    息)。

  • 出错立即返回(如果它没有任何子进程)。

  • wait等待第一个终止的子进程,而waitpid可以通过pid参数指定等待哪一个子进程

  • 调用wait将使父进程阻塞(车站买票进行等待直到出票),而调用waitpid时如
    果在options参数中指定WNOHANG可以使父进程不阻塞而立即返回0。(轮询,隔一段时间就去判断是否有票)
    wait:参数status用来保存被收集进程退出时的一些状态,它是一个指向int类型的指针。但如果我们对这个子进程是如何死掉的毫不在意,只想把这个僵尸进程消灭掉,(事实上绝大多数情况下,我们都会这样想),我们就可以设定这个参数为NULL
    pid_t waitpid(pid_t pid, int *status, int options);

    pid>0时,只等待进程ID等于pid的子进程,不管其它已经有多少子进程运行结束退出了,只要指定的子进程还没有结束,waitpid就会一直等下去。

    pid=-1时,等待任何一个子进程退出,没有任何限制,此时waitpid和wait的作用一模一样。

    pid=0时,等待同一个进程组中的任何子进程,如果子进程已经加入了别的进程组,waitpid不会对它做任何理睬。

    pid<-1时,等待一个指定进程组中的任何子进程,这个进程组的ID等于pid的绝对值。

options:
如果使用了WNOHANG参数调用waitpid,即使没有子进程退出,它也会立即返回,不会像wait那样永远等下去。

返回值:
1.和wait一样正常结束时返回清理的进程id
2.设置了WNOHANG并且没有检测到该进程则返回0
3.如果调用中出错,则返回-1,这时errno会被设置成相应的值以指示错误所在;

如何避免“僵尸”进程

1.让僵尸进程的父进程来回收,父进程每隔一段时间来查询子进程是否结束并回收,调用wait()或者waitpid(),通知内核释放僵尸进程

2.让僵尸进程变成孤儿进程,由init回收,就是让父亲先死

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值