殭屍程式,孤兒程式,wait,exit,execl等函式使用要點

wzm10455發表於2013-01-15

程式號為1的程式是所有程式的主先程式init

如何檢視程式:ps uax

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

int main()
{
    pid_t pid;
    int a = 8;
    printf("current process id:%d\n",getpid());
    pid = fork();
    if( pid > 0 )//父程式所做之事
    {
        printf("a = %d\n",a);
        printf(" pid = %d\n",pid);//子程式
        printf(" ppid = %d\n",getpid());//父程式
        //while(1);
    }else if( pid == 0 )//子程式所做之萬
    {
        a++;
        printf("aa = %d\n",a);
        printf("child pid = %d\n",getpid());//子程式
        printf("parent pid = %d\n",getppid());//父程式
        //while(1);
    }else{
        printf("fork error!\n");
    }

    exit(0);
}
/*
 *    fork函式:
 *    1.fork函式用於建立子程式。子程式
 *    繼承父程式之前執行的一切狀態,並
 *    且拷貝父程式的地址空間,成為父
 *    程式的一個副本。子程式從fork函式
 *    的下一句話開始執行。
 *    2.fork函式不能保證父程式和子程式
 *    哪個先執行。
 *    這裡相當於兩個程式在執行,所以出現的結果是六個
 */

結果:

current process id:1995
a = 8
 pid = 1996
 ppid = 1995
aa = 9
child pid = 1996
parent pid = 1995


殭屍程式的產生:

/*
 ============================================================================
 Name        : jianshiprocess.c
 Author      :
 Version     :
 Copyright   : Your copyright notice
 Description : Hello World in C, Ansi-style
 ============================================================================
 */
//長生殭屍程式
#include <stdio.h>
#include <stdlib.h>
#include<unistd.h>
#include<sys/types.h>
//殭屍程式:
//子程式在父程式前退出,此時子程式成為殭屍程式。
//孤兒程式:
//父程式在子程式之前退出,此時子程式成為孤兒程式,此子程式由init程式零養,(也就是說init程式成為子程式的父程式,init程式是所有孤兒程式的父程式)
//著兩種都是要避免的


int main(void)
{
    pid_t pid;
    pid=fork();
    if(pid>0)
    {
        sleep(10);//讓父程式等在這裡,之後被喚醒
    }
    else if(pid==0)
    {
        printf("child%d",getpid());
        printf("p%d",getppid());
        exit(0);//成為殭屍程式後,佔用程式好
    }
    else
    {
        puts("wrong");
        exit(0);
    }
    return EXIT_SUCCESS;
}

孤兒程式:


/*
 ============================================================================
 Name        : guerprocess.c
 Author      :
 Version     :
 Copyright   : Your copyright notice
 Description : Hello World in C, Ansi-style
 ============================================================================
 */

#include <stdio.h>
#include <stdlib.h>
#include<unistd.h>
#include<sys/types.h>
int main(void) {
    int i;
    pid_t pid;
    printf("current process id:%d\n",getpid());
    pid=fork();

    if(pid>0)
    {
        exit(0);//成為殭屍程式後,佔用程式好
    }
    else if(pid==0)
    {
        for(i=0;i<20;i++)
        {
            printf("child:%d\n",getpid());
            printf("parent:%d\n",getppid());
        }
    }
    else
    {
        puts("wrong");
        exit(0);
    }
    return EXIT_SUCCESS;
}


奇怪的現象:如果在這個程式的執行過程中,按ctrl+c阻止程式的進行,會發現阻止不了,因為此時的子程式成了孤兒程式,成了主程式的守護程式,因為它的父程式是init程式,而ctrl+c只能阻止前臺執行的程式



2:

return 與exit的區別:

return 用於函式返回,只有main函式呼叫時,程式才退出

而exit函式被呼叫,此程式直接退出


exit與_exit的相同點:

都是用於程式退出。

不同點:

exit函式在程式退出之前,會重新整理檔案緩衝區到檔案中。

_exit在程式退出之前,不會重新整理緩衝區,也就說直接丟棄緩衝區裡面的內容


fork與vfork

執行fork建立子程式時,子程式將拷貝父程式的資料段、堆段和棧段,此時父子程式的資料一致當互相獨立,各不影響,子程式對資料的處理不影響父程式。(其實當父子程式都不對三個段進行寫操作時,父子程式仍然共享資料段、堆段和棧段,當有任何一方有寫操作時,才產生副本,這種方式成為寫是複製)

vfork與fork區別有兩點:1、vfork建立的子程式與父程式共享資料段,2、vfork建立的子程式優先於父程式執行,當子程式執行時,父程式進入阻塞狀態。

所以vfork產生的子程式對資料的修改一定可以影響到父程式的資料

 

exit與_exit

exit:當執行exit時,終止處理程式,執行標準的I/O清楚操作(將快取中檔案寫入),呼叫atexit,呼叫_exit。由此可見,exit是加強版的_exit.

_exit:通知核心,程式結束

程式碼區別:

printf("hello");

exit(0);//

結果:輸出hello,重新整理緩衝區

printf("hello");

_exit(0)

結果,不輸出,直接丟棄緩衝區裡面的內容

3.wait函式:

wait(等待子程式中斷或結束)
相關函式
waitpid,fork
表標頭檔案
#include<sys/types.h>
#include<sys/wait.h>
定義函式
pid_t wait (int * status);
函式說明
wait()會暫時停止目前程式的執行,直到有訊號來到或子程式結束。如果在呼叫wait()時子程式已經結束,則wait()會立即返回子程式結束狀態值。子程式的結束狀態值會由引數status 返回,而子程式的程式識別碼也會一快返回。如果不在意結束狀態值,則
引數
status可以設成NULL。子程式的結束狀態值請參考waitpid()。
返回值
如果執行成功則返回子程式識別碼(PID),如果有錯誤發生則返回-1。失敗原因存於errno中。
使用時注意的幾個地方:

1.呼叫到wait函式的程式直接阻塞

2.一般由父程式呼叫,用於回收子程式退出時,其所佔有的資源,避免其成為殭屍程式

3.如果一個程式呼叫到此函式,且其沒有子程式,wait函式直接返回

4.處理SIGCHL訊號(當子程式狀態改變時,核心會向其父程式傳送SIGCHL訊號,使用者程式對於此訊號的預設處理方式為忽略)

5.呼叫到wait函式程式的任何一個子程式退出,此函式返回。(或者搜到SIGCHL函式則也退出)

6.獲取子程式的狀態值wait(&status)

如:exit(7),7是整形常量,佔32位,取整形常量的低八位,放在status的32位的高八位,如果把status裡面的值右移八位,就又變成7(status是個整形變數),因為它的低八位要被其它訊號量佔用.(exit裡面的值只能是0-255)

一個wait只能回收一個子程式的空間

7.無法確定回收某個指定的子程式



j程式一旦呼叫了wait,就立即阻塞自己,由wait自動分析是否當前程式的某個子程式已經退出,如果讓它找到了這樣一個已經變成殭屍的子程式,wait就會收集這個子程式的資訊,並把它徹底銷燬後返回;如果沒有找到這樣一個子程式,wait就會一直阻塞在這裡,直到有一個出現為止。

引數status用來儲存被收集程式退出時的一些狀態,它是一個指向int型別的指標。但如果我們對這個子程式是如何死掉的毫不在意,只想把這個殭屍程式消滅掉,(事實上絕大多數情況下,我們都會這樣想),我們就可以設定這個引數為NULL,就象下面這樣

  1. pid = wait(NULL);  

如果成功,wait會返回被收集的子程式的程式ID,如果呼叫程式沒有子程式,呼叫就會失敗,此時wait返回-1,同時errno被置為ECHILD。

如果引數status的值不是NULL,wait就會把子程式退出時的狀態取出並存入其中,這是一個整數值(int),指出了子程式是正常退出還是被非正常結束的(一個程式也可以被其他程式用訊號結束,我們將在以後的文章中介紹),以及正常結束時的返回值,或被哪一個訊號結束的等資訊。由於這些資訊被存放在一個整數的不同二進位制位中,所以用常規的方法讀取會非常麻煩,人們就設計了一套專門的巨集(macro)來完成這項工作,下面我們來學習一下其中最常用的兩個:

1,WIFEXITED(status)這個巨集用來指出子程式是否為正常退出的,如果是,它會返回一個非零值。

(請注意,雖然名字一樣,這裡的引數status並不同於wait唯一的引數--指向整數的指標status,而是那個指標所指向的整數,切記不要搞混了。)

2, WEXITSTATUS(status)當WIFEXITED返回非零值時,我們可以用這個巨集來提取子程式的返回值,如果子程式呼叫exit(5)退出,WEXITSTATUS(status)就會返回5;如果子程式呼叫exit(7),WEXITSTATUS(status)就會返回7。請注意,如果程式不是正常退出的,也就是說,WIFEXITED返回0,這個值就毫無意義。

/*
 ============================================================================
 Name        : wait.c
 Author      :
 Version     :
 Copyright   : Your copyright notice
 Description : Hello World in C, Ansi-style
 ============================================================================
 */
//多用於父程式和多程式中
#include <stdio.h>
#include <stdlib.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<unistd.h>

int main(void) {
    pid_t pid;
    int status;
    pid=fork();
    if(pid>0)
    {
        wait(&status);
        printf("this is a parent process\n");
        if(WIFEXITED(status))
        {
            printf("status is %d \n",WEXITSTATUS(status));
        }
        exit(0);
    }
    else if(pid==0)
    {
        printf("this is a child process!\n");
        exit(7);
    }
    else
    {
        printf("fork error!\n");
        exit(1);
    }
    return EXIT_SUCCESS;
}
4.wait_pid



waitpid(等待子程式中斷或結束)
相關函式
wait,fork
表標頭檔案
#include<sys/types.h>
#include<sys/wait.h>
定義函式
pid_t waitpid(pid_t pid,int * status,int options);
函式說明
waitpid()會暫時停止目前程式的執行,直到有訊號來到或子程式結束。如果在呼叫wait()時子程式已經結束,則wait()會立即返回子程式結束狀態值。子程式的結束狀態值會由引數status返回,而子程式的程式識別碼也會一快返回。如果不在意結束狀態值,則引數status可以設成NULL。引數pid為欲等待的子程式識別碼,其他數值意義如下:
pid<-1 等待程式組識別碼為pid絕對值的任何子程式。
pid=-1 等待任何子程式,相當於wait()。
pid=0 等待程式組識別碼與目前程式相同的任何子程式。
pid>0 等待任何子程式識別碼為pid的子程式。
引數option可以為0 或下面的OR 組合
WNOHANG 如果沒有任何已經結束的子程式則馬上返回,不予以等待。
WUNTRACED 如果子程式進入暫停執行情況則馬上返回,但結束狀態不予以理會。
子程式的結束狀態返回後存於status,底下有幾個巨集可判別結束情況
WIFEXITED(status)如果子程式正常結束則為非0值。
WEXITSTATUS(status)取得子程式exit()返回的結束程式碼,一般會先用WIFEXITED 來判斷是否正常結束才能使用此巨集。
WIFSIGNALED(status)如果子程式是因為訊號而結束則此巨集值為真
WTERMSIG(status)取得子程式因訊號而中止的訊號程式碼,一般會先用WIFSIGNALED 來判斷後才使用此巨集。
WIFSTOPPED(status)如果子程式處於暫停執行情況則此巨集值為真。一般只有使用WUNTRACED 時才會有此情況。
WSTOPSIG(status)取得引發子程式暫停的訊號程式碼,一般會先用WIFSTOPPED 來判斷後才使用此巨集。
           wait_pid(pid,&status,0);//等待指定的子程式,回收指定的子程式

execl:



execl(執行檔案)
相關函式
fork,execle,execlp,execv,execve,execvp
表標頭檔案
#include<unistd.h>
定義函式
int execl(const char * path,const char * arg,....);
函式說明
execl()用來執行引數path字串所代表的檔案路徑,接下來的引數代表執行該檔案時傳遞過去的argv(0)、argv[1]……,最後一個引數必須用空指標(NULL)作結束。
返回值
如果執行成功則函式不會返回,執行失敗則直接返回-1,失敗原因存於errno中。
範例
#include<unistd.h>
main()
{
execl(“/bin/ls”,”ls”,”-al”,”/etc/passwd”,(char * )0);
}
執行
/*執行/bin/ls -al /etc/passwd */
-rw-r--r-- 1 root root 705 Sep 3 13 :52 /etc/passwd
執行之後的語句很有可能被擦除掉,而之前的還在

相關文章