Linux 多线程(一)线程概念:线程概念、线程与进程、线程间的独有与共享、多线程与多进程、线程控制
線程概念
什么是線程
線程是進程中的一條執行流,執行程序中的某部分代碼。linux下沒有具體實現的線程,只有庫函數用pcb來實現的線程,所以可以認為,每個pcb就是一個線程,所以進程中都至少有一個線程,這些PCB共用進程中的同一個頁表和虛擬地址空間,比傳統的進程更加輕量化,所以這些線程在linux下也被稱為輕量級進程。
PCB也就是進程控制塊,在Linux下PCB可以實現對程序的調度運行,所以可以將其作為一個執行流,來實現線程
為什么要使用線程呢?
線程與進程
線程與進程
進程:是一個程序的動態執行,是系統資源分配的基本單位
線程:線程是進程中的一條執行流,是CPU調度的基本單位
我之前博客提到的進程其實都是單線程的進程,在linux其實每個pcb就可以理解為一個執行流,也就是一個線程
從這兩幅圖可以看出來,linux下的進程其實是一個線程組,一個進程中可以包含多個線程,每一個線程都是進程中的一條執行流(PCB),這些線程在進程的內部運行,本質也就是在進程的虛擬地址空間中運行
線程之間共用進程中的同一個虛擬地址空間,通過同一個頁表來完成映射
線程間的獨有與共享
既然線程都處于同一個進程中,共用同一個虛擬地址空間和頁表,那么它們之間還有哪些數據共享,哪些數據獨有呢?
獨有:
- 標識符(唯一的標識符來區分線程)
- 棧(獨有的函數棧,防止調用棧紊亂)
- 寄存器(也就是PCB中的上下文數據,程序計數器,內存指針等)
- 信號屏蔽字(因為信號會打斷進程當前操作,讓他優先處理信號,但是一個信號只需要一個執行流去執行即可,如果不想該線程被打斷,則對該信號屏蔽,讓其他線程去執行)
- errno(系統調用完畢后重置的一個全局變量,防止被其他線程覆蓋)
- 優先級(各有各的調度優先級)
共享
- 虛擬地址空間(代碼段/數據段, 線程之間數據和代碼都共享)
- 文件描述符表(io信息)
- 信號處理方式(信號是針對整個進程的,所以處理方式應該都一樣)
多線程與多進程
如果需要進行多任務處理,有兩種方法,一種是多線程,一種是多進程
多進程
多線程
多線程的優點:
- 線程的創建和銷毀成本低(從上面的圖可以看出來,創建多個線程只需要創建多個PCB)
- 線程間調度成本低(使用同一個頁表,調度切換時不用切換頁表)
- 線程間通信更加靈活(共用同一個虛擬地址空間,數據段共享,只需要獲取地址即可訪問數據)
多進程的優點:
- 更具有健壯性,更加穩定(因為異常,系統調用,信號等都是對整個進程生效,一旦出現進程出問題會影響所有線程)
共同優點
- IO密集型程序:多任務并行處理(單磁盤可以并行壓縮IO等待事件/多磁盤可以實現同時處理)
- CPU密集型程序:程序中進行大量的數據運算處理,CPU資源足夠,則可以同時處理,提高效率(線程數為CPU核心數+1,多出來的一個是當某一線程阻塞時頂替用的。如果創建進程過多,會增加切換調度的成本)
線程控制
前面也說過了,Linux本身是沒有線程的,只有庫函數中通過PCB來模擬的線程。在用戶態調用庫函數創建一個線程,其本質就是在內核中創建一個輕量級進程來實現程序的調度。
創建線程:
int pthread_create(pthread_t *thread,const pthread_attr_t *attr,void *(*start_routine)(void*),void *arg);thread:輸出型參數,用來獲取線程ID–線程的操作句柄
attr:用于設置線程屬性,通常置NULL
start_routine:函數指針,線程的入口函數,線程會去運行這個函數,函數運行結束后,線程退出。
arg:需要傳遞給線程的入口函數的參數
頭文件:#include<pthread.h>
返回值:成功返回0,失敗返回非0
終止線程:
當線程執行完入口函數就會退出,但也可以通過調用對應的接口退出。
退出一個線程
void pthread_exit(void *retval);和exit()不同,exit是退出整個進程
線程退出接口,哪個線程調用就退出哪個線程
retval:退出返回值
主線程退出,并不會導致進程退出,只有全部線程退出了進程才會退出。
終止一個線程
int pthread_cancel(pthread_t thread);線程等待:
線程有一個默認的屬性,joinable,處于這個屬性的線程,退出后需要被其他線程等待獲取返回值并且釋放資源。
默認情況下,線程是必須被等待的,如果不等待,則會造成資源泄露
等待指定線程退出,獲取其返回值。
并且該函數會阻塞,線程沒有退出則一直等待。
線程分離:
將joinable的屬性修改為detach屬性
joinable:退出后需要被其他線程等待獲取返回值并且釋放資源。
detach:退出后自動釋放資源,不需要被等待
如果不想獲取返回值,也不想等待線程退出,就可以使用線程分離
int pthread_detach(pthread_t pthread)線程id
pthread_t pthread_self(void)返回調用線程的tid
在這里就要提一提tid與pid的區別,以及對于一個進程,我們看到的進程的pid到底是什么
tid:用戶態線程的id,是線程的操作句柄,其實就是線程這塊空間的首地址。
pid:輕量級進程id,這就是用來模擬線程的pcb的id
tgid:線程組id,也就是主線程id,就是我們外面看到的進程的pid
總結
以上是生活随笔為你收集整理的Linux 多线程(一)线程概念:线程概念、线程与进程、线程间的独有与共享、多线程与多进程、线程控制的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C++ 泛型编程(一):模板基础:函数模
- 下一篇: Linux 多线程(二)线程安全:线程安