進程與線程的區別——源碼級別

一、線程與進程的區別

前天面試的時候被問到了進程與線程的區別,本來這種面試題想來也沒有什麼好說的我也就沒太在乎,結果他問的時候我就支支吾吾的說了他們關於資源開銷,空間管理,進程通信三個方面的情況,其實有這三個就夠了,重要的是要能夠展開說纔可以,比如說講到獨享內存你就要說到他們的安全性,調試的方便性,以及他們的從屬關係。其實說白了上面這些都是圍繞着進程獨佔內存,線程共享內存來展開的,接下來來詳細看看他們源碼級別的區別吧!

二、進程的創建

fork其實個人已經剖析過一次了,在前面內存管理的章節,它主要就是做兩件事,即複製父進程的task_struct結構與喚醒創建的進程。

1.複製進程task_struct總結
  • 分配task_struct
  • 創建內核棧,設置task_struct->stack變量
  • 複製task_struct,底層調用memcpy實現,即複製虛擬空間
  • 設置內核棧的thread_info
  • 進行權限相關的設置,如誰可以操作我,我可以操作誰等
  • 進行調度相關統計量的初始化,與調度類,調度優先級的設定
  • 複製文件描述符數組相關數據結構與進程文件系統目錄信息。
  • 複製信號相關的數據結構,如各種信號處理函數的入口等
  • 複製父進程內存空間管理相關數據結構
  • 最後分配進程ID,設置tid和group_leader.
2.喚醒子進程
  • 首先設置子進程狀態爲運行態
  • 接下來將該進程掛在CPU相關的調度類的調度隊列上,嘗試進行搶佔式調度
  • 搶佔式調度上一篇文章《進程的主動調度與搶佔式調度》已經講過,在喚醒子進程的這個函數中他就會嘗試去進行一次喚醒,若可以發生搶佔式調度就設置相關變量等待時機進行搶佔。
  • 別忘了,fork是一個系統調用,當我們從內核態返回用戶態的時候就會嘗試進行進程的調度。
3.小總結

通過以上的簡單介紹起碼知道,創建一個進程要做什麼事情,也知道了爲什麼fork系統調用無法確認兩個進程的執行順序,以及何時發生調度,怎樣發生搶佔,這個和上一講有了一個稍微密切的聯繫。

三、線程的創建

簡單來說,線程創建(也即pthread_create)是用戶態和內核態的結合,首先它會在主線程(當前進程)的堆區爲新創建的線程創建用戶態的棧,之後會調用clone系統調用(底層還是fork調用的那些函數,只不過參數不一樣)引用一些主線程的數據結構,注意是加一個引用,類似C++的智能指針那樣,最後當從系統調用返回的時候就會調用我們設置的用戶態線程函數。

四、線程與進程源碼級別的區別

  • 進程是資源分配的最小單位,線程是CPU調度的最小單位
  • 進程獨佔內存空間,線程共享內存空間
    個人認爲其實區別就是上面的兩點,網上好多所謂的區別其實大都是第二條派生出來的,我們看到第二條其實就應該可以立刻想到諸如線程安全性,通信的便利性,線程死亡的安全性,系統資源開銷問題以及所謂的從屬關係。
    來瞅一瞅,由上面對線程創建的簡單介紹之後我們應當知道,它會在調用clone系統調用的時候是直接引用計數的,故它在創建和銷燬也就方便的多了,不像進程一樣要逐項複製文件系統、內存管理等一些臭大臭大的數據結構,所以它的系統開銷也會小很多,同時正是由於這種共享關係的存在,假設我們某個線程出了問題了收到了致命信號,那麼就相當於是所有的線程都收到了,故我們常說一個線程死了那麼整個進程就死了,至於從屬關係其實還是由task_struct結構體來設計完成的,通信的便利性就更不用說了,就線程的棧是在進程的堆區創建這一個性,就可以發現每一個線程的數據(自然包括主線程)都會被其他線程所共享,當然線程的局部數據是不允許共享的,但線程的私有數據可以呀!所以這樣通過層層分析我們就可以發現對於內核來說哪兒來的進程和線程,他們只不過都是一個個CPU調度實體而已,在內核是擁有相同的地位。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章