西安網(wǎng)站外包臺州做優(yōu)化
進程的回收
1.wait
原型
pid_t wait(int *status);
功能:該函數(shù)可以阻塞等待任意子進程退出
??????并回收該進程的狀態(tài)。
??一般用于父進程回收子進程狀態(tài)。
參數(shù):status?進程退出時候的狀態(tài)
??如果不關(guān)心其退出狀態(tài)一般用NULL表示
??如果要回收進程退出狀態(tài),則用WEXITSTATUS回收。
返回值:
????????成功時,wait
返回終止子進程的PID。
????????失敗時,返回-1,并設(shè)置errno
來指示錯誤。
關(guān)于子進程狀態(tài)的一些宏定義:
1.WIFEXITED(status)??是不是正常結(jié)束,如果返回非零值,則表示子進程正常結(jié)束了它的main
函數(shù),或者調(diào)用了exit()
函數(shù)。
2.WEXITSTATUS(status)? 為真時,使用這個宏來獲取子進程的退出狀態(tài)碼。狀態(tài)碼是由main
函數(shù)的返回值或者exit()
函數(shù)的參數(shù)決定的。
3.WIFSIGNALED(status)?檢查子進程是否是因為接收到信號而終止的。如果返回非零值,則表示子進程是因為信號而終止。? ??
4.WTERMSIG(status) 為真時,使用這個宏來獲取導致子進程終止的信號編號。
5.WIFSTOPPED(status)
: 檢查子進程是否因為接收到SIGSTOP
、SIGTSTP
、SIGTTIN
或SIGTTOU
信號而停止。如果返回非零值,則表示子進程已經(jīng)停止。
6.WSTOPSIG(status)
: 當WIFSTOPPED(status)
為真時,使用這個宏來獲取導致子進程停止的信號編號。
7.WIFCONTINUED(status)
: 檢查子進程是否已經(jīng)從停止(stopped)狀態(tài)繼續(xù)執(zhí)行。如果返回非零值,則表示子進程已經(jīng)繼續(xù)。
舉例:
int a=20;
int main(int argc, const char *argv[])
{pid_t ret =fork();if(ret>0){//printf("father is %d pid= %d,ppid= %d \n",a,getpid(),getppid());wait(NULL);printf("after wait\n");sleep(5);}else if(0==ret){printf("child = %d pid:%d ppid:%d",a,getpid(),getppid());sleep(3);printf("child terminal\n");exit(1);}else{perror("fork");return 1;}printf("a:%d pid:%d",a,getpid());return 0;
}
利用宏定義,判斷子進程的狀態(tài)
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
int a = 20;
int main(int argc, char *argv[])
{pid_t ret = fork();if(ret>0){//fatherprintf("father is %d pid %d ,ppid:%d \n",a,getpid(),getppid());int status;pid_t pid = wait(&status);if(WIFEXITED(status))// 代表子進程正常結(jié)束{//正常結(jié)束的子進程,才能獲得退出值printf("child quit values %d\n",WEXITSTATUS(status));}if(WIFSIGNALED(status))//異常結(jié)束{printf("child unnormal signal num %d\n", WTERMSIG(status));}printf("after wait, %d\n",status);}else if(0 == ret){//childprintf("child a is %d pid:%d ppid:%d\n",a,getpid(),getppid());sleep(5);printf("child terminal\n");exit(50);}else {perror("fork error\n");return 1;}printf("a is %d pid:%d\n",a,getpid());return 0;
}
2.waitpid
原型
#include <sys/types.h>
#include <sys/wait.h>pid_t waitpid(pid_t pid, int *status, int options);
參數(shù)說明:
pid
: 子進程的PID。如果設(shè)置為?-1
,則表示等待任一子進程,這與?wait
?函數(shù)的行為相同。status
: 指向整數(shù)的指針,用于接收子進程的狀態(tài)信息。如果不需要狀態(tài)信息,可以傳遞?NULL
。options
: 指定等待行為的選項,常用的選項有:WNOHANG
: 如果子進程尚未終止,調(diào)用立即返回,而不是掛起等待。- 0:? 表示回收過程會阻塞等待
返回值:
- 成功時,返回子進程的PID。
- 如果子進程尚未終止(使用了?
WNOHANG
?選項),返回 0。 - 失敗時,返回 -1,并設(shè)置?
errno
?以指示錯誤
練習:
設(shè)計一個多進程程序,用waitpid函數(shù)指定回收
其中的某個進程資源并將其狀態(tài)打印輸出。
其他的進程都以非阻塞方式進行資源回收。
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{int i = 0 ;pid_t ret[5]={0};printf("father pid %d ,ppid:%d \n",getpid(),getppid());for(i = 0 ;i<5;i++){ret[i] = fork();if(ret[i]>0){//father}else if(0 == ret[i]){//childprintf("child pid:%d ppid:%d\n",getpid(),getppid());sleep(rand()%5);exit(1);}else {perror("fork error\n");return 1;}}int status;while(1){pid_t pid = waitpid(ret[2],&status, WNOHANG);if(ret[2] == pid){if(WIFEXITED(status))// 代表子進程正常結(jié)束{//正常結(jié)束的子進程,才能獲得退出值printf("child quit values %d\n",WEXITSTATUS(status));}if(WIFSIGNALED(status))//異常結(jié)束{printf("child unnormal signal num %d\n", WTERMSIG(status));}printf("father recycle success, pid :%d\n",pid);break;}else if(0 == pid){printf("子進程未結(jié)束,稍后在試\n");//usleep(1000);sleep(1);}}printf("after wait, %d\n",status);return 0;
}
exec
exec函數(shù)族在 C 語言中用于在當前進程的上下文中執(zhí)行一個新的程序。exec
函數(shù)不會創(chuàng)建新的進程,而是替換當前進程的映像為新程序的映像。這意味著進程的PID保持不變,但是執(zhí)行的程序完全改變。
exec族函數(shù)
-
????????加載并執(zhí)行由?execl(const char *path, const char *arg0, ...)
:path
?指定的程序,arg0
?是傳遞給新程序的主參數(shù),后面可以跟隨其他參數(shù),以?NULL
?結(jié)尾。 -
? ? ? ? ? 加載并執(zhí)行由?execv(const char *path, char *const argv[])
:path
?指定的程序,argv
?是一個以?NULL
?結(jié)尾的參數(shù)數(shù)組。 -
? ? ? ? ? ?與?execle(
const char *path, const char *arg0, ..., char *const envp[])
:execl
?類似,但允許指定一個新的環(huán)境指針數(shù)組?envp
,替換當前環(huán)境。 -
? ? ? ? ? ?加載并執(zhí)行由?execve
(const char *path, char *const argv[], char *const envp[])
:path
?指定的程序,argv
?是參數(shù)數(shù)組,envp
?是環(huán)境變量數(shù)組。 -
? ? ? ? ? ?與?execlp(const char *file, const char *arg0, ...)
:execl
?類似,但在 PATH 環(huán)境變量中搜索程序?file
。 -
? ? ? ? ? ?與?execvp(const char *file, char *const argv[])
:execv
?類似,但在 PATH 環(huán)境變量中搜索程序?file
。 -
? ? ? ? ? ?與?execvpe
(const char *file, char *const argv[], char *const envp[])
:execve
?類似,但在 PATH 環(huán)境變量中搜索程序?file
,并允許指定新的環(huán)境變量數(shù)組?envp
。
舉例:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[])
{// firefox www.baidu.com //execl("/usr/bin/firefox","firefox","www.baidu.com",NULL);// env echo $PATH ls -l --color=auto ll//execlp("ls","ls","-l","--color=auto",NULL);char *const args[]={"ls","-l","--color=auto",NULL};//execv("/bin/ls",args);//vector// pathexecvp(args[0],args);//vector+pathprintf("看見就錯了\n");exit(1);return 0;
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[])
{// firefox www.baidu.com //execl("./aaa","aaa","1","2","3",NULL);// env echo $PATH ls -l --color=auto ll//execlp("./aaa","aaa","1","2","3",NULL);char *const args[]={"aaa","1","2","3",NULL};//execv("./aaa",args);//vector// pathexecvp("./aaa",args);//vector+patha//如果需要都能調(diào)用成功,第一個參數(shù)都傳 路徑+文件名printf("看見就錯了\n");exit(1);return 0;
}