多程式函式系列fork(), wait(), exec()系列,system(), posix_spawn()例項詳解
fork():
fork()用來建立一個子程式,該子程式是執行該函式的父程式的一個複製的映像;
#include <unistd.h>
pid_t fork(void);
注意:fork()函式有一個特點是一次呼叫返回兩個值;
如果返回值為0,則是子程式;如果返回值大於0,則是父程式(此時返回值就是子程式的PID);(如果返回值為-1,則建立子程式失敗)
問題就在於為什麼這個fork()函式會返回兩個不同的值呢???
當執行了該函式的時候已經建立了一個子程式的程式空間,fork()會在父程式空間返回一個值(子程式PID),同樣也會在子程式空間中返回一個值(0);
wait():
wait函式是在父程式中使用,用來獲取子程式的狀態;#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);
wait系統呼叫會使父程式暫停執行,直到它的等待的子程式結束為止。也就是說wait是阻塞的。
wait可以返回兩個資訊,直接返回子程式的PID,還有status(注意這個值不是在子程式中呼叫exit函式中的退出碼,下面有專門的巨集使用該status),子程式的退出狀態資訊存放在wait的引數status指向的記憶體中。
WIFEXITED(status)//如果子程式正常退出,那麼返回1;見例項輸出結果;
WEXITSTATUS(status)//返回子程式的退出碼;如果退出碼的值很大,那麼它只會返回退出碼的低八位
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():
waitpid用來等待某個特定程式的結束,可以指定等待子程式的PID;
引數options:允許改變waitpid的行為,最有用的一個選項是WNOHANG,它的作用是防止waitpid把呼叫者的執行掛起,也就是說父程式不會暫停執行;也就是說waitpid此時是非阻塞的:如果pid指定的目標子程式還沒有結束或意外終止,則waitpid立即返回0;如果目標子程式確實正常退出了,在返回該子程式的pid。waitpid呼叫失敗時返回-1並設定errno。
如果waitpid函式中的pid為-1,那麼它就和wait函式一樣,即等待任意一個子程式結束。
引數的status的含義是一樣的。
例項1:fork(), wait()例項
/*************************************************************************
> 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);
}
例項2:fork(), waitpid()例項,建立兩個子程式,只是等待第二個子程式,並且設定為非阻塞
/*************************************************************************
> 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);
}
父程式用SIGCHLD來處理子程式
我們知道在事件已經發生的情況下執行非阻塞的呼叫才能提高程式的效率。對於waitpid函式而言,我們最好在某個子程式退出之後再呼叫它。那麼父程式怎麼知道子程式退出了呢?這個可以靠訊號SIGCHLD來解決。當一個程式結束時,它將給其父程式傳送一個SIGCHLD訊號。我們可以在父程式中捕獲SIGCHLD訊號,並在訊號處理函式中呼叫非阻塞的waitpid以徹底結束一個子程式。
實現程式碼如下:
/*************************************************************************
> 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秒之後才退出。exec系列函式:
當我們呼叫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函式:
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);
}
posix_spawn():
例項5: posix_spawn()
見之前寫的部落格:http://blog.csdn.net/linux_ever/article/details/50295105
最後總結一下非同步程式和同步程式
非同步程式和同步程式
非同步程式:各個程式可以同時執行,也可以不同時執行;
同步程式:各個程式不可以同時執行;
fork(), fork()-exec(), posix_spawn()建立的程式都是非同步程式;
system()建立的程式是同步程式;
相關文章
- 多程式程式設計函式posix_spawn例項程式設計函式
- 例項詳解 Linux 中的 fork() 函式Linux函式
- 【多程式】Linux中fork()函式詳解|多程式Linux函式
- Linux下程式相關:fork(),wait(),exec()LinuxAI
- APUE 8-1 fork函式例項函式
- Linux系統程式設計(9)—— 程式之程式控制函式exec系列函式Linux程式設計函式
- wait()函式詳解AI函式
- PHP函式處理函式例項詳解PHP函式
- 【函式】oracle translate() 詳解+例項函式Oracle
- Linux 中的 fork() 函式例項解析Linux函式
- PHP exec system passthru系統函式PHP函式
- linux中fork()函式詳解Linux函式
- fork 和 vfork 使用的注意事項和 system() 函式的替代函式
- PHP類和物件函式例項詳解PHP物件函式
- hive視窗分析函式使用詳解系列一Hive函式
- IOCP 系列函式講解函式
- linux系統程式設計之程式(五):exec系列函式(execl,execlp,execle,execv,execvp)使用Linux程式設計函式
- hasOwnProperty()函式程式碼例項函式
- exec()函式函式
- 多執行緒函式系列pthread_create(), pthread_join(), pthread_self(),pthread_exit(), pthread_detach()例項詳解執行緒函式thread
- hive視窗分析函式使用詳解系列二之分組排序視窗函式Hive函式排序
- exec函式族函式
- exec函式簇函式
- fork waitAI
- fork函式與vfork函式函式
- Mysql系列第十講 常用的幾十個函式詳解MySql函式
- vfork函式例項函式
- jQuery css()函式使用程式碼例項jQueryCSS函式
- js冪函式程式碼例項分享JS函式
- 類設計系列 --- 解構函式篇 (轉)函式
- SQL視窗分析函式使用詳解系列三之偏移量類視窗函式SQL函式
- 例項程式碼詳解正規表示式匹配換行
- find命令的exec選項用法詳解(轉)
- js函式作為函式的引數程式碼例項JS函式
- fork()與vfork()函式函式
- fork與vfork函式函式
- 多執行緒系列(十九) -Future使用詳解執行緒
- Sql Server資料庫開窗函式Over()的使用例項詳解SQLServer資料庫函式