Linux - 線程基礎概念

理解線程,必須先理解進程!!
什麼是進程(PCB)
  • 進程pid - 進程有很多,需要有一個區分和標識
  • 內存指針 - 進程運行時需要依賴代碼和數據,所以有一個內存指針指向進程所需要的代碼和數據,指向虛擬地址空間
  • 進程有很多,而CPU只有幾個,那麼進程就需要調度,爲了實現調度,進程還有以下的信息,爲調度做輔助
    • 進程的狀態(R,S,T,t,X,Z)
    • 上下文信息 - 記錄進程進行到哪裏,從哪裏開始
    • 優先級
    • 記賬信息 - 要統計進程在CPU上執行的時間和多少指令,是進程什麼時候從CPU離開的依據
  • files指針 - 指向一個結構體,內含 fd_array(文件描述符表)
  • 未決信號集/信號屏蔽字
線程解決的問題

  • 解決“一心多用”問題 - 能夠幾遍只有一個CPU,也可以同時做多件事情,並且不受影響
  • 充分利用多核CPU資源 - 讓多個CPU併發的執行任務中的一部分,從而縮短整體的運行時間

什麼是線程

  • 線程是能夠運行和調度的最小單位
  • 是進程實際運作的單位
  • 是進程中單一順序的執行流(例如,一個進程中的main函數,是由線程執行起來的)
  • 一個進程可以併發執行多個線程

進程和線程

  • 進程/任務是資源分配和管理的基本單位
  • 線程/輕量級進程 (這個叫法只針對於Linux而言,別的OS下不一定是,因爲在Linux上) 是程序調度和執行的基本單位
  • 線程共享進程數據,但也擁有自己的一部分信息
線程ID : 線程的唯一標識符
一組寄存器 :線程的上下文信息
棧 :每個線程都維護者自己的一個棧
errno
信號屏蔽字
調度優先級
  • 我們平常說的pid(getpid() 得到的),其實是這個進程的唯一標識符,也是這個進程中主線程的唯一標識符

主線程是創建進程時產生的第一個線程,也就是main函數創建的線程。

在Linux上
線程是由一個PCB描述的,進程是由一組PCB描述的。
在操作系統內核中,並不區分進程線程,只管理PCB,進程和線程的概念是在用戶層上的。
我們可以採用進程的方式,模擬實現線程,將操作統一在一起。

//進程和task_struct 形成 1:N 的關係
struct task_struct
{
    ...
    pid_t pid; //線程id,每個PCB的id,唯一
    pid_t tgid; //線程組id ,我們使用gitpid() 獲得的其實是t_gid
    ...
    struct task_struct* group_leader; //指向組長的PCB
    ...
    struct list_head thread_group; //在進程的任何一個線程中都可以通過這個鏈表找到其他的線程
    ...
};
主線程的pid和tgid是相同的,所以進程的pid就是組長pcb的id

一進程的多個線程共享

  • 同一虛擬地址空間(重要!) : 數據段和代碼段都是共享的,如果定義了一個函數,那麼這個進程中的所有線程都可以調用,如果定義了一個全局變量,這個全局變量在各個線程中都可以訪問到,如果在堆上申請了一段空間,所有的線程也都可以對這個數據進行操作
  • 文件描述符表(重要!):一個線程修改了一個文件,其他的線程訪問到的文件也都改變
  • 共用信號處理機制中的未決信號機
  • 信號處理方式
  • 當前工作目錄
  • 用戶id和組id
  • 未決信號集 :只要進程收到了信號,也就意味着所有線程收到了信號
共享同一個虛擬地址空間,本質上其實是共用同一個頁表

線程之間獨自擁有

  • 棧(重要!) :每個線程各自有一個調用棧,線程也可以訪問其他線程棧上的信息
  • 上下文信息(一組寄存器)(重要!) :爲了執行調度的正確性,產生上下文信息
  • 線程id
  • errno :函數出錯就會在errno中設置錯誤碼,我們調用perror時會自動解析錯誤碼
  • 信號屏蔽字
  • 優先級調度
線程的優點(與進程對比)

  • 創建一個新的線程的佔用資源小於進程
創建一個進程,我們需要給他分配虛擬地址空間,這個空間佔用了一部分資源,比如我們的堆默認爲8M,耗費的時間當然比較大
創建一個線程,線程的很對區域都是和其他線程共享的,所以節約了很多的資源,增快了效率,銷燬也比較快
  • 線程之間的切換代價很小
兩進程之間的切換,因爲佔用的空間和資源比較多,所以切換效率比較低
兩線程的切換,只用切換一小部分數據,效率較高
  • 線程之間共享數據比較容易
線程可以看到所有自己線程組中線程的信息
進程之間需要管道、消息隊列...
  • 能夠成分利用多處理器的可並行數量
比如我們現在是4核CPU,現在需要不停歇的進行CPU的運算操作,當前用四個線程運算操作,CPU佔用率可達到400%(Linux下),可見充分利用了硬件資源

線程的缺點

  • 缺乏訪問控制,這導致線程使用起來安全性比較低
線程之間不獨立,很有可能訪問到其他線程的數據,使程序發生未定義行爲
一個線程異常終止,很可能導致所有線程異常終止
  • 編程難度大大增加
編寫和調試一個多線程程序的難度比單線程的難度困難的多
多線程公用同一個公共資源,這個資源就成爲了臨界資源,訪問臨界資源的代碼就是臨界區,多進程訪問臨界資源很可能出現數據錯亂的情況。
  • 線程穩定性
如我們是4核CPU,現在有8個線程,期中4個線程在執行任務的時候,其他4個線程就在等待,也會和正在執行任務的線程競爭,消耗資源,而且很容易導致整個進程都掛掉
發佈了77 篇原創文章 · 獲贊 50 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章