fork()用来创建一个子进程,该子进程是执行该函数的父进程的一个复制的映像;
#include <unistd.h> pid_t fork(void);
#include <sys/types.h> #include <sys/wait.h> pid_t wait(int *status); pid_t waitpid(pid_t pid, int *status, int options); int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);
WIFEXITED(status) returns true if the child terminated normally, that is, by calling exit(3) or _exit(2), or by returning from main(). WEXITSTATUS(status) 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) returns the number of the signal that caused the child process to terminate. This macro should be employed only if WIFSIGNALED returned true. WCOREDUMP(status) returns true if the child produced a core dump. This macro should be employed only if WIFSIGNALED returned true. This macro is not speci‐ fied in POSIX.1-2001 and is not available on some UNIX implementations (e.g., AIX, SunOS). Only use this enclosed in #ifdef WCOREDUMP ... #endif. WIFSTOPPED(status) returns true if the child process was stopped by delivery of a signal; this is possible only if the call was done using WUNTRACED or when the child is being traced (see ptrace(2)). WSTOPSIG(status) returns the number of the signal which caused the child to stop. This macro should be employed only if WIFSTOPPED returned true. WIFCONTINUED(status) (since Linux 2.6.10) returns true if the child process was resumed by delivery of SIGCONT.
waitpid用来等待某个特定进程的结束,可以指定等待子进程的PID;
参数options:允许改变waitpid的行为,最有用的一个选项是WNOHANG,它的作用是防止waitpid把调用者的执行挂起,也就是说父进程不会暂停执行;也就是说waitpid此时是非阻塞的:如果pid指定的目标子进程还没有结束或意外终止,则waitpid立即返回0;如果目标子进程确实正常退出了,在返回该子进程的pid。waitpid调用失败时返回-1并设置errno。
如果waitpid函数中的pid为-1,那么它就和wait函数一样,即等待任意一个子进程结束。
参数的status的含义是一样的。
/************************************************************************* > File Name: simple_fork.cpp > Author: > Mail: > Created Time: 2015年12月15日 星期二 14时52分24秒 ************************************************************************/ #include <iostream> #include <unistd.h> #include <cstdlib> #include <sys/types.h> #include <sys/wait.h> using namespace std; int main(int argc, char *argv[]) { pid_t pid; cout << "This is main process, PID is " << getpid() << endl; pid = fork(); if (pid < 0){ cout << "fork error..." << endl; exit(-1); } else if (pid == 0){//This is the child process cout << "This is child process, PID is " << getpid() << endl; sleep(3);//子进程休眠3秒,这样就可以看到wait函数阻塞了父进程,因为三秒之后,wait语句下面的语句才开始执行 exit(11);//将子进程的退出码设置为11 } else{//This is the main process cout << "This is main process waiting for the exit of child process." << endl; int child_status; pid = wait(&child_status); cout << "This is main process. The child status is " << child_status << ", and child pid is " << pid << ", WIFEXITED(child_status) is " << WIFEXITED(child_status) << ", WEXITSTATUS(child_status) is " << WEXITSTATUS(child_status) << endl; } exit(0); }
/************************************************************************* > File Name: simple_fork.cpp > Author: > Mail: > Created Time: 2015年12月15日 星期二 14时52分24秒 ************************************************************************/ #include <iostream> #include <unistd.h> #include <cstdlib> #include <sys/types.h> #include <sys/wait.h> using namespace std; int main(int argc, char *argv[]) { pid_t pid; int i = 0; cout << "This is main process, PID is " << getpid() << endl; for (i = 0; i < 2; ++i){ pid = fork(); if (pid < 0){ cout << "fork error..." << endl; exit(-1); } else if (pid == 0){//This is the child process cout << "This is child process, PID is " << getpid() << endl; exit(11);//将子进程的退出码设置为11 } else{//This is the main process cout << "This is main process waiting for the exit of child process." << endl; } } int child_status; pid_t child_pid2; sleep(1);//一定要等待,因为waitpid设为了无阻塞的,如果不等待,当执行完waitpid下面的语句的时候子进程2可能还没有退出,那么就得不到它的退出码了 child_pid2 = waitpid(pid, &child_status, WNOHANG); cout << "This is main process. The second child status is " << child_status << ", and child pid is " << child_pid2 << ", WIFEXITED(child_status) is " << WIFEXITED(child_status) << ", WEXITSTATUS(child_status) is " << WEXITSTATUS(child_status) << endl; exit(0); }
/************************************************************************* > File Name: sigchld.cpp > Author: > Mail: > Created Time: 2016年03月02日 星期三 21时29分36秒 ************************************************************************/ #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> #include <signal.h> void sigchld_handler(int signum) { int status; pid_t pid; if((pid = waitpid(-1, &status, WNOHANG)) < 0){ printf("waitpid error\n"); return; } printf("The signal is %d, child:%d exit status is %d\n", signum, pid, WEXITSTATUS(status)); } //不可被信号终端的睡眠函数 void unbreak_sleep(int sec) { while(sec > 0){ sec = sleep(sec); } } int main() { signal(SIGCHLD, sigchld_handler); pid_t pid = fork(); if(pid < 0){ printf("fork error\n"); return -1; } else if(pid == 0){//子进程 printf("子进程:%d....等待3秒之后退出,退出码是100\n", getpid()); sleep(3); printf("子进程退出\n"); exit(100); } else if(pid > 0){//父进程 printf("父进程:%d,创建的子进程的pid = %d, 父进程等待7秒\n", getpid(), pid); //sleep(7); unbreak_sleep(7); } printf("父进程退出\n"); exit(0); }输出:
父进程:17365,创建的子进程的pid = 17366, 父进程等待7秒 子进程:17366....等待3秒之后退出,退出码是100 子进程退出 The signal is 17, child:17366 exit status is 100 父进程退出值得注意的是sleep是可中断睡眠,它会被信号打断。比如在父进程中调用sleep(7)等待的时候,当父进程执行完信号处理函数之后会直接退出。但是当在父进程中调用的是unbreak_sleep(7)的情况下,执行完信号处理函数之后会接着等待直到等待了7秒之后才退出。
当我们调用fork()创建了一个进程之后,通常将子进程替换成新的进程映象,这可以用exec系列的函数来进行。当然,exec系列的函数也可以将当前进程替换掉。
#include <unistd.h> extern char **environ; 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 execvpe(const char *file, char *const argv[], char *const envp[]);总结:函数名字中l(函数中的字母l不是数字1)代表可变参数列表,函数名字中p代表在path环境变量中搜索file文件。envp代表环境变量
实例3:fork()和exec()函数系列
/************************************************************************* > File Name:fork_exec.cpp > Author: > Mail: > Created Time: 2015年12月15日 星期二 14时52分24秒 ************************************************************************/ #include <iostream> #include <unistd.h> #include <cstdlib> #include <sys/types.h> #include <sys/wait.h> using namespace std; int main(int argc, char *argv[]) { pid_t pid; char *arg[] = {"ls", "-l", NULL}; cout << "This is main process, PID is " << getpid() << endl; pid = fork(); if (pid < 0){ cout << "fork error..." << endl; exit(-1); } else if (pid == 0){//This is the child process cout << "This is child process, PID is " << getpid() << endl; //execl("/bin/ls", "ls", "-l", NULL); //execlp("ls", "ls", "-l", NULL); //execle("/bin/ls", "ls", "-l", NULL, NULL); //execv("/bin/ls", arg); //execvp("ls", arg); execve("/bin/ls", arg, NULL);//上面的六个函数的运行结果都是一样的 exit(11);//将子进程的退出码设置为11 } else{//This is the main process cout << "This is main process waiting for the exit of child process." << endl; int child_status; pid = wait(&child_status); cout << "This is main process. The child status is " << child_status << ", and child pid is " << pid << ", WIFEXITED(child_status) is " << WIFEXITED(child_status) << ", WEXITSTATUS(child_status) is " << WEXITSTATUS(child_status) << endl; } exit(0); }
system执行参数中的可执行文件;也是运行起来另外一个进程;
调用该函数会创建一个shell来执行系统命令或可执行文件;父进程被挂起,直到子进程结束且system()调用返回;
#include <stdlib.h> int system(const char *command
/************************************************************************* > File Name: system.cpp > Author: > Mail: > Created Time: 2015年12月15日 星期二 16时46分16秒 ************************************************************************/ #include <iostream> #include <cstdlib> using namespace std; int main(int argc, char **argv) { int status; cout << "This is main process..." << endl; status = system("ls -l"); //status = system("ls"); if(status < 0){ cout << "system is error." << endl; exit(-1); } cout << "WEXITSTATUS(status) is " << WEXITSTATUS(status) << endl; exit(0); }
实例5: posix_spawn()
见之前写的博客:http://blog.csdn.net/linux_ever/article/details/50295105
最后总结一下异步进程和同步进程
异步进程和同步进程
异步进程:各个进程可以同时执行,也可以不同时执行;
同步进程:各个进程不可以同时执行;
fork(), fork()-exec(), posix_spawn()创建的进程都是异步进程;
system()创建的进程是同步进程;