進程概念

進程:
一、概念:是一個正在執行的可執行程序實例。
二、構成:進程信息存放在進程控制塊PCB的數據結構中。

三、數據結構:
在Linux中描述進程的數據結構是task_struct;
task_struck是Linux內核中的一種數據結構,包含着進程信息存放在內存中。

task_struct //內容
{
1、標識符:pid ,ppid 進程的唯一標識符,用於區分其它進程
2、狀態:任務狀態,退出碼,退出信號
3、優先級:相對其它進程的優先級
4、程序計數器:程序中將要執行下一條指令的地址
5、內存指針:程序代碼和數據相關的指針,還有其它進程共享內存塊的指針
6、上下文數據:進程執行時處理器中的寄存器信息(用於進程恢復,休學例子)
7、I/O狀態信息:包括顯示的I/O請求,分配給進程的I/O設備和被進程使用的文件列表。
8、記賬信息:包括處理器的時間總和,使用的時鐘總數,時間限制,記賬號等。
9、其它信息
};

四、進程狀態:
R—-就緒狀態(運行)—進程運行
S—-睡眠—-進程睡眠時(sleep)
D—-磁盤休眠(不可中斷睡眠)
T—-停止—-給進程發送:kill -19 進程pid ,此時(R/S)進程變爲停止態,發送SIGCONT繼續運行。
t—-跟蹤狀態(等待跟蹤進程對它的控制)
X—-死亡狀態(進程正常退出,異常退出等)
Z—-殭屍狀態

殭屍進程:
子進程先退出,且父進程未回收子進程的退出信息,導致子進程變爲殭屍進程。
殭屍進程不可被直接殺死,只能通過殺死父進程,殺死子進程。
原因:父進程退出後,父進程會獲取子進程狀態信息,回收子進程資源。
殭屍進程代碼:

#include<stdio.h>
#include<unistd.h>

int main()
{
    pid_t pid = fork();

    if(pid > 0)
    {
        printf("父進程:%d\n",getpid());
        while(1)
            sleep(2);
    }

    if(pid == 0)
        printf("子進程:%d\n",getpid());

    return 0;
}

//殭屍進程:
//子進程先退出,且父進程未回收子進程的退出信息,導致子進程變爲殭屍進程。
//殭屍進程不可被直接殺死,只能通過殺死父進程,殺死子進程。
//原因:父進程退出後,父進程會獲取子進程狀態信息,回收子進程資源。

//孤兒進程:
//父進程先退出,子進程未退出變爲孤兒進程。
//孤兒進程會被1號進程領養。由1號進程控制,獲取信息,回收資源。

孤兒進程:
父進程先退出,子進程未退出變爲孤兒進程。
孤兒進程會被1號進程領養。由1號進程控制,獲取信息,回收資源。
孤兒進程代碼:

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>

int num = 0;
int main()
{
    pid_t pid = fork();
    if(pid == 0)
    {
        num = 100;
        while(1)//每隔2s打印一次子進程信息
        {
            printf("子進程num = %d pid = %d ppid = %d\n",num,getpid(),getppid());
            sleep(2);//父進程退出後子進程變爲孤兒進程,ppid = 1
        }
    }

    if(pid > 0)
    {
        printf("父進程num = %d pid = %d ppid = %d\n",num,getpid(),getppid());
        sleep(3);//3s後父進程退出
    }

    if(pid < 0)
    {
        perror("fork");
        exit(-1);
    }
    return 0;
} 

//查看進程信息: ps axu | grep 進程名
//退出(殺死)進程:kill -9 進程pid

五、進程常見指令
查看進程設置指令:kill -l;
殺死進程:kill -9 進程pid
查看進程優先級:ps -l 或 ps -elf
查看進程:ps axu 或top(類似任務管理器)

六、組織進程方式:
所有運行的進程都以task_struct鏈表的形式存放在內存中。

七、進程的性質:
併發性:多個進程在同一時間段內,同時執行,訪問共享資源採用使程切換實現。
並行性:多個進程在多個cpu上,同一時刻同時運行。
競爭性:進程數目多於資源數,所以進程之間存在競爭的屬性,爲了高效的完成任務,便有了優先級。
獨立性:多進程之間,進程獨享資源,互不干擾。

八、同步與互斥:
進程互斥:多個進程同時訪問共享資源,但資源只能分配給一個進程使用,所產生的現象。
進程同步:多個進程相互協作完成同一任務。

九、創建進程:fork(),vfork()
1、創建子進程:父進程會將自己的PCB,代碼,緩衝區拷貝一份給子進程。
2、父,子進程的pid,ppid不同。
3、父進程設置的文件鎖不會被子進程繼承
4、子進程未處理的鬧鐘會被清除
7、子進程的未處理信號集設置爲空。

注:父子進程打開同一文件:父,子進程的表項各自獨立,但共用一個文件,對文件操作存在干擾。
子進程關閉文件,並不是直接關閉,而是計數器減1,計數器爲0時才關閉文件。

fork創建子進程:
1、fork創建的子進程有兩個返回值。
父進程返回子進程的pid,子進程返回0
2、子進程以父進程爲模板(PCB,數據,代碼),父子進程代碼共享,數據各自開闢空間私有一份(採用寫實拷貝)
通常父子代碼共享,父子不在寫操作時,數據也是共享的,當任意一方寫操作時,便以寫時拷貝的方式各自私有一份數據

父進程—–虛擬地址—–頁表映射—–物理地址(父)
子進程—–虛擬地址—–頁表映射—–物理地址(子)
父子進程各種有一個虛擬地址(通常4G)和頁表,所以父子進程可能存在相同的地址(虛擬)。但數據可能不相同(數據存在物理內存中)。
父子進程數據不寫操作時,指向同一物理地址。寫操作時,子進程會將父進程的數據拷貝一份下來,在進行寫操作。

3、fork成功返回子進程的pid,失敗返回-1。
失敗原因:1、系統中線程太多,達到最大值
2、用戶線程超過了限制。
4、fork之後父子進程繼續執行,誰先執行由調度器決定(通常子進程執行3s後父進程再執行)
5、注意緩衝區問題,父進程會將緩衝區的內容拷給子進程。
若fork之後,有輸出:
未進行行刷新—-父進程的緩衝區拷給子進程,所以有兩次輸出
進行行刷新—-父子進程競爭緩衝區,入無延時有一次輸出,有延時兩次輸出。

行緩衝:將內容直接向顯示器上輸出,按行刷新緩衝區。
全緩衝:將內容重定向寫到其它文件中

printf條件顯示:
(1)、使用’\n’;
(2)、調用:fflush(stdout);
(3)、緩衝區滿了
(4)、遇到scanf獲取緩衝區
(5)、進程或線程退出

6、無條件限制時,每遇到一個fork進程數擴大二倍。
7、父子進程相對獨立,各自擁有代碼,數據,內存空間,棧幀結構等。執行不影響其它進程的數據,棧幀等。

vfork創建進程:
1、不會拷貝內存空間,就算寫時也不拷貝。共用一個頁表和內存空間。
2、父進程在子進程執行完之後才執行。
3、必須使用exec或exit退出進程,不可使用return
原因:父子進程共用一塊內存空間,共用一個棧幀結構。當子執行return後函數棧幀被銷燬,父進程無棧幀或棧幀破壞,此時再執行父進程導致出錯。
4、建議不要使用vfork創建進程,容易出錯。

注:
若父進程先退出,子進程未退出,子進程變爲孤兒進程,孤兒進程由1號進程領養,管理和回收子進程的資源。
若子進程先退出,且父進程未接收子進程的狀態,管理子進程,則子進程變爲殭屍進程。
殭屍進程有內存泄漏的危險。
殭屍進程不可被殺死:kill -9 pid也不可殺死
防止產生殭屍進程方法:進程等待

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章