天天看點

Linux程序建立與管理Linux程序建立與管理

Linux程序建立與管理

在Linux系統中,除了系統啟動之後的第一個程序由系統來建立,其餘的程序都必須由已存在的程序來建立,新建立的程序叫做子程序,而建立子程序的程序叫做父程序。那個在系統啟動及完成初始化之後,Linux自動建立的程序叫做根程序。根程序是Linux中所有程序的祖宗,其餘程序都是根程序的子孫。具有同一個父程序的程序叫做兄弟程序

1. 建立子程序fork()

使用fork()系統調用可以建立一個子程序

首先要明白一個概念:程序控制塊 PCB (Process Control Block),它是描述程序狀态、資源、和相關程序關系的一種資料結構(比如程序狀态、排程資訊、辨別符等等),是程序的标志,與程序共存亡。

程序=程式+PCB

Linux程式建立與管理Linux程式建立與管理

首先來看個小栗子:

#include<stdio.h>
int count1 = 0;
int main(){
        int pid;
        int count2 = 0;
        count1++;
        count2++;
        printf("count1 = %d, count2 = %d\n", count1, count2);

        pid = fork();
        count1++;
        count2++;
        printf("count1 = %d, count2 = %d\n", count1, count2);
        printf("pid = %d\n", pid);

        return 0;
}
           

程式的運作結果為:

Linux程式建立與管理Linux程式建立與管理

然後分析

  1. 使用fork()函數在一個程序中分裂出一個子程序,主要工作就是建立了一個新的控制塊PCB,并未在記憶體中給子程序配置獨立的程式運作空間,而隻是簡單地将程式指針指向父程序的代碼,是以①處是父程序執行的結果,而子程序不會再執行了,是以隻會輸出一遍count1 = 1, count2 = 1。
  2. 兩個程序具有各自的資料區和使用者堆棧,在函數fork()生成子程序時,将父程序資料區和使用者堆棧的内容分别複制給了子程序。同時,接下來的内容,父程序和子程序都是對自己的資料區和堆棧中的内容進行修改運算了,是以父子程序輸出的都是count1 = 2, count2 = 2,即②③所示。
  3. 在子程序中

    pid = 0

    (沒啥理由~),父程序中pid儲存的是建立好的子程序的程序号,即④⑤所示。

2. 檢視程序号getpid(), getppid()

linux下,getpid()可以傳回目前程序程序号, getppid()可以傳回目前程序父程序号

看下面這個栗子:

#include<stdio.h>
int main(){
        int pid;
        pid = fork();
        if(pid == 0)
                printf("我是子程序 ");
        else
                printf("我是父程序 ");
        printf("pid = %d, ppid = %d \n", getpid(), getppid());
        return 0;
}
           

程式執行結果:

Linux程式建立與管理Linux程式建立與管理

可以看到建立的子程序的父程序pid為157,即建立它的父程序号,如果父程序已經結束,那麼子程序的gitppid()會是多少?

下面這個栗子,子程序sleep 2秒鐘,此時父程序以及結束,可以看到此時父程序id為1,為init()程序。

#include<stdio.h>
int main(){
        int pid;
        pid = fork();
        if(pid == 0){
                printf("我是子程序 ");
                sleep(5);
        }
        else{
                sleep(3);
                printf("我是父程序 ");
        }
        printf("pid = %d, ppid = %d \n", getpid(), getppid());
        return 0;
}
           
Linux程式建立與管理Linux程式建立與管理

3. 終結程序exit()

如果一個程序調用exit(),那麼這個程序會立即退出運作,并負責釋放被中止程序除了程序控制塊之外的各種核心資料結構。這種隻剩下“身份證”的程序叫做“僵屍程序”。

exit(int status)就是退出,傳入的參數是程式退出時的狀态碼,0表示正常退出,其他表示非正常退出,一般都用-1或者1。父程序可以使用wait()函數擷取,wait函數可以參考後面。

看下面這個栗子

#include<stdio.h>
int main(){
        int pid;
        pid = fork();
        if(pid == 0){
                printf("我是子程序 ");
                sleep(5);
                exit(0);
        }
        else{
                printf("我是父程序 ");
        }
        return 0;
}
           

輸出結果如下

Linux程式建立與管理Linux程式建立與管理

4. 程序的阻塞wait()

wait()函數功能是:父程序一旦調用了wait就立即阻塞自己,由wait自動分析是否目前程序的某個子程序已經退出,如果讓它找到了這樣一個已經變成僵屍的子程序,wait就會收集這個子程序的資訊,并把它徹底銷毀後傳回;如果沒有找到這樣一個子程序,wait就會一直阻塞在這裡,直到有一個出現為止

這裡給出僵屍程序和孤兒程序的概念

  • 孤兒程序:一個父程序退出,而它的一個或多個子程序還在運作,那麼那些子程序将成為孤兒程序。孤兒程序将被init程序(程序号為1)所收養,并由init程序對它們完成狀态收集工作;
  • 僵屍程序:一個程序使用fork建立子程序,如果子程序退出,而父程序并沒有調用wait或waitpid擷取子程序的狀态資訊,那麼子程序的程序描述符仍然儲存在系統中。這種程序稱之為僵死程序(也就是程序為中止狀态,僵死狀态)。

wait函數原型:

pid_t wait(int * status);

傳回值為子程序的pid(失敗傳回-1),status用于擷取子程序的狀态碼。下圖是status後16位的劃分,正常退出低8位為0,816為退出狀态(0255)

Linux程式建立與管理Linux程式建立與管理

下面這個栗子,父程序就會等待子程序結束再結束~

#include<stdio.h>
int main(){
        int pid, status = 0, subpid = 0;
        pid = fork();
        if(pid == 0){
                printf("我是子程序\n");
                sleep(5);
                exit(10);
        }
        else{
                printf("我是父程序\n");
                subpid = wait(&status);
                if((status & 0xff) == 0)
                        printf("正常傳回,子程序pid = %d, 傳回狀态碼 status = %d\n", subpid, (status>>8)&0xff);
                else
                        printf("傳回異常\n");
        }
        return 0;
}
           
Linux程式建立與管理Linux程式建立與管理

繼續閱讀