1、fork():
创建子进程
pid_t fork(void);
函数的作用:用于创建子进程。
包含头文件:
#include <sys/types.h>
#include <unistd.h>
返回值:
fork()的返回值会返回两次。一次是在父进程中,一次是在子进程中。
在父进程中返回创建的子进程的ID,
在子进程中返回0
在父进程中返回-1,表示创建子进程失败,并且设置errno
写时复用,(vfork()函数基本废弃。)
2、exec():
子进程中执行别的程序,参考该文
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[]);
例子:
int main()
{
puts("begin");
fflush(NULL); //exec函数组前需要刷新所有的流
execl("/bin/date","date","+%s",NULL);//参数是从argv[0]开始的,即从进程名开始的
perror("execl()");//如果execl成功的话,该语句不执行,执行的话,肯定是失败了。
exit(-1);
puts("end");
exit(0);
}
结果:begin可以打印,end无法打印。
注意:因为前面有puts,故在exec前要使用fflush(NULL),如果是在终端中输出是没有问题的,
但如果是重定向到文件时,begin是打印不出来的。因为还没有输出呢,就被exec给替换了。这一点与fork类似。
3、wait():
用在父进程中等待子进程结束后,回收子进程,解除阻塞;若子进程一直没有退出,则阻塞住父进程。
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status)
wait函数是没有指向的,不针对特定的子进程。
wait函数是死等的,必须等到子进程退出,如果子进程没有退出,则就阻塞在这个地方。
成功:返回终止进程的ID。
失败:返回-1
status,返回的是进程的退出状态,如果不关心该状态,则置为NULL。
#include <sys/types.h>
#include <sys/wait.h>
pid_t waitpid(pid_t pid,int *status,int options)
waitpid(-1,&status,0) 等价于 wait(&status);
二者相同的参数 status:
若关心退出状态,则需通过一系列的宏来表明退出状态:
WIFEXITED(status) :是否正常终止。如果正常终止,则返回值为return true.
WEXITSTATUS(status):正常结束的(即WIFEXITED(status)返回真)同时使用该宏,返回结束值,即exit()的参数。(与上一宏连用)
WIFSIGNALED(status):返回true,如果子进程被信号终止(异常退出)。
WTERNSIG(status):如果WIFSIGNALED(status)返回真,(子进程被信号打断,)则返回打断的信号编码。(与上一宏连用)
WCOREDUMP(status):如果WIFSIGNALED(status)返回真,判断,是否产生core dump文件。(与上上一宏连用)
WIFSTOPED(status):如果子进程是stopped by delivery of a signal. 则返回真。
WSTOPSIG(status);如果WIFSTOPED(status)为真,则返回stop的信号。(与上一宏连用)
WIFCONTINUED(status);如果是被stoped ,检测有没有信号将进程继续,有则返回true.(与上上一宏连用????)
waitpid的 option参数,是个位图:
参数为:
0 :阻塞,死等pid 子进程
WNOHANG :立即返回,如果没有子进程退出,相当于将阻塞变为非阻塞。
waitpid的pid 参数:
<-1 :收进程group id = pid的绝对值任何一个子进程。
-1:收任何一个子进程。
0:收与父进程同组process group ID任何的子进程,//没有进程号为0的进程
>0: 指定的子进程id号
命令:ps ajx 查看组ID.
注意:
1)为了避免僵尸进程,fork要与wait成对出现。
2)exec则一般是与fork连用,运行一个新的进程任务。
例1:
#include <QCoreApplication>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
pid_t pid,son_pid;
pid = fork();
if(pid<0)
{
perror("fork");
}else if(pid==0)
{
printf("this is son,pid=%d\n",getpid());
sleep(10);
printf("son exit\n");
exit(0);
}else{
printf("this is father,pid=%d\n",getpid());
son_pid = wait(NULL);
printf("father catch son pid = %d\n",son_pid);
printf("father exit\n");
exit(0);
}
}
运行结果:
通过运行结果发现:子进程和父进程的名字是一样的。
父进程调用wait后,阻塞住等待子进程结束,回收子进程资源。
int main()
{
pid_t pid;
puts("beigin");
fflush(NULL);
pid = fork();
if(pid<0)
{
perror("fork()");
exit(1);
}
if(pid == 0)
{
execl("/bin/date","date","+%s",NULL);
perror("execl");
exit(1);
}
wait(NULL);
puts("end");
exit(0);
}