gdb调试:
1.set follow-fork-mode child 命令设置gdb在fork之后跟踪子进程
2.set follow-fork-mode prarent 设置跟踪父进程
exec函数族:
简单来说就是当程序执行了fork()(此时程序分出父进程),默认情况下父进程有的代码子进程也有,但是如果有了exec这个函数,子进程中的所有代码会被清空,去执行你指定的一个程序,比如写了exec(a.out),那么子进程将执行的是a.out这个程序。
但是子进程PID没有变,还是父进程的儿子,只是它的灵魂变了。
execlp函数:
实例:execlp(“ls”, “-l”, “-d”, “-h”, NULL);
我想让子进程执行ls命令且在后面跟了若干参数,参数可以任意指定但是需要告诉函数我的参数到哪为止,其中NULL就是告诉函数参数没有了。
函数原型:int execlp(const char *file, const char *arg, …);
关于函数返回值:通过man此函数,只有当函数出错时会返回一个 -1 和 设置errno。
根据实际运行来看,实例代码基本没有现象,这是因为参数有误,因为参数调用是从argv[0]开始的,比如:./a.out aa bb cc 其中第一个参数是a.out,而实例中将“-l”设置成了第一个参数。
修改后:execlp(“ls”, “ls”, “-l”, “-h”, NULL);
这里删除了“-d,因为“-d”只显示当前目录不显示其下面的文件所以现象不明显(只会打印出一个".")。
扩展:这里父进程的父进程就是bash,它执行它的子进程,也是通过exec函数来完成的。
execl函数:
函数原型:int execl(const char *path, const char *arg, …);
可以从参数看出和上面那个函数差别在于execl函数需要指定路径,而execlp函数只需指定文件名即可。其它一样。
实例:execl("./a,out", “./a.out”, NULL);//有参数加参数没有参数就这样
如果要执行“ls”,那么写法将是:execl("/bin/ls", “ls”, “-l”, NULL);这也可以看出差别。
execvp函数:
和execlp函数差别在于,将参数部分封装在一起了
实例:
1.execlp(“ls”, “ls”, “-l”, “-h”, NULL);
2.char *argv[] = { “ls”, “-l”, “-h”, NULL} ;
execvp(“ls”, argv);
函数原型:int execvp(const char *file, char *const argv[]);
exec函数族调用成功就执行新的程序不返回,所以只在出错时返回。此函数以上举得例子都是子进程中执行就是
if(pid == 0)
{
exec........;//函数写在这里
}
回收子进程:
**孤儿进程:**父进程先于子进程结束,子进程变成了孤儿,此时子进程的父进程将变成init,init进程领养了子进程。实质就是进程回收
**僵尸进程:**进程终止,父进程尚未回收,子进程残留资源(PCB)存放于内核中,变成了僵尸进程。子进程在回收之前都处于僵尸态。因为子进程结束后是不能立马被回收的。比如父进程在一直死循环,此时子进程结束父进程是不能正常回收的,且父进程没有结束那么子进程就不能被init收养,从而变成了僵尸进程。
僵尸进程不能被kill,所以需要先kill了它的父进程,这样这个僵尸进程就变成了了孤儿进程,这样就可以被init收养,但是init发现收养的是一个僵尸随即就将它回收了,从而达到了回收的效果。
wait函数:
1.阻塞等待子进程退出
2.回收子进程残留资源
3.获取子进程结束状态(退出的原因)
原型:pid_t wait(int *status);
参数:回收进程的状态
成功返回:子进程ID
失败返回:-1
实例:
1.wait(&status)//可以获取子进程结束原因
2.wait(NULL)//不关心子进程的结束原因
它的返回值需要运用到宏函数进行操作,可以在man里查看
WIFEXITED(status)//为真说明子进程正常终止
returns true if the child terminated normally, that is, by call‐
ing exit(3) or _exit(2), or by returning from main().
WEXITSTATUS(status)//获取退出的状态(exit状态)
returns the exit status of the child. This consists of the
least significant 8 bits of the status argument that the child
specified in a call to exit(3) or _exit(2) or as the argument
for a return statement in main(). This macro should be employed
only if WIFEXITED returned true.
WIFSIGNALED(status)//为真说明子进程被信号终止
returns true if the child process was terminated by a signal.
WTERMSIG(status)//取得暂停程序的那个信号编号,如:kill -11 。。。则返回11
returns the number of the signal that caused the child process
to terminate. This macro should be employed only if WIFSIGNALED
returned true.
可以在指令中输入:kill -l 看信号编号的宏长什么样
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP
6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1
11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM
16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP
21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR
31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3
38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8
43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7
58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2
63) SIGRTMAX-1 64) SIGRTMAX
waitpid函数:
函数原型:pid_t waitpid(pid_t pid, int *status, int options);
返回值:
- 大于0的值:表示回收成功的子进程ID
- 0:函数调用时, 参数3指定WNOHANG,并且没有子进程结束
- -1:失败
WNOHANG return immediately if no child has exited.//这个宏的意思是如果没有子进程结束立刻返回,就是非阻塞。
参数pid:
- 大于0:回收指定ID的子进程(如果取反则回收的是一个组,一般情况是这个子进程下面还有一系列的子进程)
- -1:回收任意子进程
- 0:回收和当前调用waitpid一个组(进程组)的所有子进程
- 小于-1:回收指定进程组内的任意子进程
不论是wait还是waitpid都只能回收一个进程。