歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux基礎 >> 關於Linux

有關Linux下父子進程之間的幾個思考與結論

1 . 父進程可以利用wait()/ waitpid()等待子進程的結束,避免僵死子進程的產生,當然也可以循環的wait()/ watipid()來等待所有的子進程的結束;最好可以用法是,在子進程結束時,會向父進程發送的SIGCHLD信號,父進程通過signal()/sigaction()來響應子進程的結束.具體實例可參考:TestFork4.c,關鍵代碼如下:
signal(SIGCHLD, sigchld_handler);
void sigchld_handler(int sig)
{
pid_t pid;
int status;
for(; (pid =waitpid(-1, &status, WNOHANG)) >0;)
{
printf("child %d died:%d\n", pid, WEXITSTATUS(status));// pid, status);
}
//while((pid =waitpid(-1, &status, WNOHANG))>0){}
return;
}

2 . 當父進程結束時,還未結束的子進程就會成為孤兒進程,系統會把init進程作為其父進程;從而使得子進程在父進程結束後,繼續運行.

3 . 對於父子進程共存時,產生相關信號如SIGINT時,父子進程都能接受到此信號,只是先由父進程響應,再由父進程把此信號傳遞給子進程;但要注意的地方是:(1)如父進程沒有對該信號進程自定義處理,則父子進程都接受信號的默認處理,eg:在沒有對SIGINT進程自定義處理時,產生此信號,由父子進程都馬上中止;(2)如父進程自定義了信號處理方法,則子進程一樣接受此信號和其信號處理方法;此時,若子進程成為孤兒進程,則此時的子進程不會再接受此信號和其信號處理方法.具體實例可參考 TestFork6.c,關鍵代碼如下:
signal(SIGINT, sig_handler);
for(i =0; i<5; i++)
{
if(fork() ==0)
{
printf("child %d\n", getpid());
sleep(5);//此刻,響應SIGINT信號,且信號處理完後喚醒進程
printf("after sleep1:child %d\n", getpid());
sleep(5);//到此刻,子進程成為孤兒進程,因此不再響應SIGINT信號
printf("after sleep2:child %d\n", getpid());
exit(0);
}
}

4 . 在創建子進程時,內核將父進程的很多內容拷貝給子進程,同時在調用fork()後,父子進程共享正文部分(其實也相當於拷貝);注意拷貝兩字,所以子進程中修改的東東對父進程沒有作用,除非利用父子進程通信方法;因此,要特別注意子進程的代碼編寫,如動態空間的釋放問題,內存信號修改問題;具體實例可參考:TestFork1.c,關鍵代碼如下:
gets(buf);
pid =fork();
if(pid ==0)
{
printf("child:");
strcpy(buf, "xiaofeng");
//此處的buf(為主進程中buf的一個副本)與else(主進程)中的buf無關,因為對其修改不會影響主進程中buf的內容
}
else
{
printf("parent:");
sleep(5);
}
printf("%s\n", buf);//此處輸出結果處決於該語句位於哪個進程(父/子進程)
結果:(hello 為gets(buf)語句)
hello
child:xiaofeng
parent:hello

 

5 . 補充下有關信號的幾個結論:
(1)信號處理有三種模式,一為默認處理方式;二為信號忽略方式;三為自定義信號處理方法;
(2) 當一個進程睡眠在可中斷優先級時,進程捕獲的信號將中斷進程的睡眠


//補充,添加多線程
Linux下的多線程模型的特點:

Linux下的線程實質上是輕量級進程(light weighted process),線程生成時會生成對應的進程控制結構,只是該結構與父線程的進程控制結構共享了同一個進程內存空間。 同時新線程的進程控制結構將從父線程(進程)處復制得到同樣的進程信息,如打開文件列表和信號阻塞掩碼等。由於我們是在子線程生成之後修改了信號阻塞掩碼,此刻子線程使用的是主線程原有的進程信息,因此子線程仍然會對SIGINT和SIGTERM信號進行反應,因此當我們用Ctrl+C發出了SIGINT信號的時候,主進程不處理該信號,而子進程(線程)會進行默認處理,即退出。子進程退出的同時會向父進程(線程)發送SIGCHLD信號,表示子進程退出,由於該信號沒有被阻塞,因此會導致主進程(線程)也立刻退出,出現了前述的運行情況。因而該問題的一個解決方法是在子線程生成前進行信號設置, 或在子線程內部進行信號設置。 由於子線程是往往是一個事務處理函數,因此我建議在簡單的情況下采用前者,如果需要處理的信號比較復雜,那就必須使用後一種方法來處理。

 

------------------------------------------補充: 僵屍進程


Unix: 僵死(Zombie)進程

進程在它的生命周期有幾種狀態:睡眠,可運行,停止,正在運行和僵死狀態。所謂僵死進程,指的是一個進程已經退出,它的內存和相關的資源已經被內核釋放掉,但是在進程表中這個進程項(entry)還保留著,以便它的父進程得到它的退出狀態。一個進程退出時,它的父進程會收到一個SIGCHLD信號。一般情況下,這個信號的句柄通常執行wait系統調用,這樣處於僵死狀態的進程會被刪除。如果父進程沒有這麼做,結果是什麼呢?毫無疑問,進程會處於僵死狀態。實際上,僵死進程不會對系統有太大的傷害,最多就是它的進程號(PID)和進程表中的進程項系統不能使用。

一個父進程fork了一個子進程出來,然後它們兩個就各自執行自己的代碼,在某一時刻,子進程退出了。但是此時子進程還有一定的空間並沒有被操作系統回收。需要父進程使用wait系列的系統調用對該子進程進行回收,這樣子進程就能夠完全地從系統中消失。
所以僵屍進程就是說子進程在退出之後到被父進程回收之前的這段時間。

子進程死後,會發送SIGCHLD信號給父進程。

Copyright © Linux教程網 All Rights Reserved