1. 程式人生 > >進程和線程(待續)

進程和線程(待續)

恢復 手動 復制 初始化 完成 vol 較高的 工作目錄 屏蔽

一、定義

教科書式回答,進程是資源分配的最小單位,而線程是CPU調度的最小單位。

進程有自己的獨立地址空間(虛擬的,4G大小),一個進程崩潰後不會對其他進程產生影響。同一進程內的某一個線程崩潰後,整個進程也崩潰了。因為線程有自己的堆棧和局部變量,但線程之間沒有單獨的地址空間。

多進程比多線程程序要健壯,但是由於切換時更耗費資源和時間,所以有高並發需求時,一般采用多線程。

想要分清進程和線程的區別,我們先來看一下進程的獨立地址空間中包含哪些內容。

進程的虛擬獨立地址空間主要包含以下內容:

Text Segment、Data Segment()、BBS(未初始化數據區)、stack、heap、內核空間

TextSegment 表示程序的代碼段

DataSegment (全局初始化數據區/靜態數據區,或簡稱數據段)表示 已經初始化且初值非0的全局變量和靜態局部變量 ;
BBS(未初始化數據區-特指全局變量和靜態局部變量)表示未初始化或初始值為0的全局變量和靜態局部變量;操作系統負責這些段的加載並分配內存空間,這些段在編譯期就分段完成。在程序執行前初始化為0或者NULL指針。

(stack)用於存儲局部變量、函數參數、函數返回值

(heap)用於存儲程序動態申請的內存,需要程序員手動釋放。因為空閑空間的內存是不連續的,所以堆在操作系統中是用鏈表來存儲的。

內核空間(kernel space)屬於操作系統的一部分,常駐內存。

 1 int a = 0; 全局初始化區
 2 char *p1; 全局未初始化區
 3 
 4 void    main()
 5 {
 6     int b; 棧
 7     char s[] = "abc"; 棧 s和"abc"都是棧上
 8     char *p2; 棧
 9     char *p3 = "123456"; 123456\0在常量區,p3在棧上。
10     static int c =0; 全局(靜態)初始化區
11     p1 = (char *)malloc(10);  堆
12     p2 = (char *)malloc(20);  堆
13 }

這下知道每個進程空間存放那些東西了吧。我們接著看多進程。

進程上下文

進程上下文:一個進程在執行的時候,CPU的所有寄存器中的值、進程的狀態以及堆棧上的內容。內核在進行進程的切換時,需要保存當前進程的所有狀態,即保存當前進程的上下文,以便再次執行該進程時,能夠恢復切換時的狀態,繼續執行。

一個進程只會有一個父進程,所以任意一個子進程都可以通過調用getppid()函數獲取其父進程的進程ID.

多進程

fork()函數調用成功後,將為子進程申請PCB和用戶內存空間.子進程是父進程的副本.在用戶空間將復制父進程用戶空間所有數據(代碼段、數據段、BBS、堆、棧),復制父進程內核空間PCB中的絕大多數信息.子進程從父進程繼承下例屬性:有效用戶、組號、進程組號、環境變量、對文件的執行時關閉標誌、信號處理方式設置、信號屏蔽集合、當前工作目錄、根目錄、文件模式掩碼、文件大小限制和打開的文件描述符(特別註意:共用同一文件表項)。我可以認為父子進程都幾乎是相同的,因為他們擁有相同的系統資源(除了各自的PID不一樣)嗎?

多線程

線程不再獨有虛擬地址空間,而是和同一進程內的其他線程共享地址空間。但是線程各自擁有獨立的寄存器(不然還用volatile幹嘛)和堆棧(比如各線程的局部變量)。

多線程 vs 多進程

    • 多線程之間堆內存共享,而進程相互獨立,線程間通信可以直接基於共享內存來實現,比進程的常用的那些多進程通信方式更輕量。
    • 在上下文切換來說,不管是多線程還是都進程都涉及到寄存器、棧的保存,但是線程不需要切換 頁面映射(虛擬內存空間)、文件描述符等,所以線程的上下文切換也比多進程輕量
    • 多進程比多線程更安全,一個進程基本上不會影響另外一個進程
      在實際的開發中,一般不同任務間(可以把一個線程、進程叫做一個任務)需要通信,使用多線程的場景比多進程多。但是多進程有更高的容錯性,一個進程的crash不會導致整個系統的崩潰,在任務安全性較高的情況下,采用多進程。

進程和線程(待續)