標籤:資料 多線程 編程 線程 進程
進程及線程基本定義
進程(process)
處於執行期的程式及其所包含資源的總稱
程式:可執行程式代碼
資源:開啟檔案、掛起訊號、地址空間、資料區段等
線程(thread)
進程中活動的對象
有獨立的程式計數器、進程棧及一組進程寄存器
節省主存、減少管理開銷、快速切換
進程
資源分派單位
進程的上下文組成
進程式控制制塊PCB:包括進程的編號、狀態、優先順序以及本文段和資料區段中資料分布的大概情況
本文段(text segment):存放該進程的可執行代碼
資料區段(data segment):存放進程靜態產生的資料結構
使用者堆棧(stack)
線程
CPU調度基本單位
進程執行狀態相關資訊
進程 ID、進程組 ID、使用者識別碼和組 ID 工作環境(Environment) 工作目錄(Working directory)程式指令(Program instructions) 寄存器(Registers) 棧(Stack) 堆(Heap) 檔案描述符(File descriptors) 訊號(Signal actions ) 共用庫(Shared libraries) 處理序間通訊手段(Inter-process communication tools)
線程的基本特點
是進程的一個實體,可作為系統獨立調度和指派的基本單位
有不同的狀態,有控制線程的各種原語,包括建立和撤銷線程等
不擁有系統資源(只擁有從屬進程的全部資源,資源是分配給進程)
一個進程中的多個線程可並發執行
進程中建立的線程可執行同一程式的不同部分
也可以執行相同代碼
系統開銷小、切換快
進程的多個線程都在進程的地址空間活動,共用全域變數
同一進程中的多個線程共用該進程的虛擬空間
進程程式碼片段
進程的公有資料
利用這些共用的資料,線程很容易的實現相互連訊
進程開啟的檔案描述符
訊號的處理器
進程的目前的目錄和進程使用者ID與進程組ID
說明
對不同進程來說,具有獨立的資料空間,資料傳遞只能通過通訊的方式進行,這種方式費時而不方便
線程是實現並發的必要條件
線程ID
每個線程都有自己唯一的線程ID
寄存器組的值
建立線程時,須將原有線程的寄存器集合的狀態儲存
線程的堆棧
線程必須擁有自己的函數堆棧,使得函數調用可以正常執行,不受其他線程的影響
錯誤返回碼
不同線程應該擁有自己的錯誤返回碼變數
線程的訊號屏蔽碼
線程的訊號屏蔽碼應由線程自己管理,但所有線程都共用同樣的訊號處理器
線程的優先順序
使用者線程
使用者線程存在於使用者空間,通過線程庫來實現
線程庫提供對線程的建立、調度和管理的支援,而無須核心支援
核心並不知道使用者級線程,所有線程的建立和調度都在使用者空間內進行,無須核心幹預
使用者級線程的調度以進程為單位
優點
同一進程內的線程切換不需要轉換到核心,調度演算法是進程專用的
缺點
系統調度阻塞問題,不能充分利用多處理器
由作業系統直接支援,核心在其空間內執行線程的建立、調度和管理
由於線程管理由作業系統完成,因此核心線程的建立和管理要慢於使用者線程的建立和管理
優點
支援多處理器,支援使用者進程中的多線程、核心線程切換的速度快
缺點
對使用者的線程切換來說,系統開銷大
線程-多執行緒模式
多對一模型
將許多使用者級線程映射到一個核心線程
線程管理在使用者空間進行,效率較高
處理機調度的單位仍然是進程
缺點
如果一個線程執行了阻塞系統調用,那麼整個進程就會阻塞
因為任何時刻只有一個線程訪問核心,多個線程不能並行運行在多處理器上
說明
在不支援核心級線程的作業系統上所實現的使用者級線程庫也使用多對一模型
一對一模型
將每個使用者線程映射到一個核心線程
在一個線程執行阻塞時,允許另一個線程繼續執行
允許多個線程運行在多處理機系統上
提供比多對一模型更好的並發功能
缺點
建立一個使用者線程就需要建立一個相應核心線程
建立核心線程的開銷會影響應用程式的效能,這種模型的絕大多數實現限制系統所支援的線程數量
多對多模型
多工許多使用者級線程到同樣數量或更小數量的核心線程上
核心線程的數量可能與特定應用程式或特定機器有關
克服前兩種模型的缺點
開發人員可以建立任意多的必要的線程,並且相應核心線程能在多處理器系統上並行運行
當一個線程執行阻塞系統調用時,核心能調度另一個線程來執行
pthread背景
早期各硬體廠商主要使用私人版本線程庫,實現差異非常大,開發人員難於開發可移植的線程應用
為能夠最大限度的提高線程的效能,需要一個標準的編程介面
對於UNIX系統,IEEE POSIX 1003.1c標準 (1995)定義了這樣的介面
遵從該標準實現的線程被稱做POSIX線程,或pthreads
pthreads定義了一套C語言編程介面和函數調用
包括一個pthread.h標頭檔和一個線程庫
基於POSIX標準的線程編程介面包括一個pthread.h標頭檔和一個線程庫編譯方法gcc –g **.c -o *** –lpthread 功能線程管理支援線程建立/刪除、分離/聯合,設定/查詢線程屬性互斥處理同步,稱為“mutex”建立/銷毀、加鎖/解鎖互斥量,設定/修改互斥量屬性條件變數支援基於共用互斥量的線程間通訊建立/銷毀、等待/觸發特定條件變數,設定/查詢條件變數屬性
線程管理支援線程建立、分離、聯合等,還包括線程屬性的設定/查詢 互斥處理同步,稱為“mutex”提供建立、銷毀、加鎖和解鎖互斥量也包括補充的修改互斥量屬性功能,並用它去設定或者修改與互斥相關的屬性 條件變數支援基於共用互斥量的線程間通訊,以開發人員的特定條件變數為基礎。包括基於特定條件變數的建立、銷毀、等待和訊號觸發設定/查詢條件變數屬性的功能也包括在內
線程管理線程建立
函數原型int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void*),void * arg); 參數說明thread:要建立的線程id指標attr:建立線程時的線程屬性v(*start_routine)(void*):傳回值是void*類型的指標函數arg:start_routine的參數傳回值成功返回0失敗返回錯誤編號EAGAIN:表示系統限制建立新的線程,如線程數目過多EINVAL:代表線程屬性值非法
#include <pthread.h>#include <stdio.h>void *create(void *arg) {printf("new thread created ..... ");}int main(int argc, char *argv[]){ pthread_t tidp; int error; error=pthread_create(&tidp, NULL, create, NULL); if(error != 0) { printf("pthread_create is not created ... "); return -1; } printf("prthread_create is created... "); return 0;}
基本問題int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void*),void * arg); 僅允許傳遞一個參數給線程待執行的函數如何傳遞多個參數解決途徑構造一個包含所有參數的結構,將結構指標作為參數傳遞給pthread_create()所有參數必須利用(void *)來傳遞
擷取線程自身的id函數原型pthread_t pthread_self(void);傳回值調用線程的線程id比較線程ID函數原型int pthread_equal(pthread_t tid1, pthread_t tid2);參數tid1:線程1的idtid2:線程2的id傳回值相等返回非0值否則返回0
線程終止
正常終止方法1:線程自己調用pthread_exit()void pthread_exit(void *rval_ptr);rval_ptr:線程退出返回的指標,進程中其他線程可調用pthread_join()訪問到該指標方法2:線上程函數執行return 非正常終止其它線程的幹預自身運行出錯
同步方式(非分離狀態)
等待新建立線程結束
只有當pthread_join()函數返回時,建立的線程才算終止,才可釋放自己佔用的系統資源
非同步方式(分離狀態)
未被其他線程等待,自己運行結束即可終止線程並釋放系統資源
函數原型int pthread_join( pthread_t thread, void ** rval_ptr);功能調用者將掛起並等待新進程終止當新線程調用pthread_exit()退出或者return時,進程中的其他線程可通過pthread_join()獲得進程的退出狀態使用約束一個新線程僅僅允許一個線程使用該函數等待它終止被等待線程應處於可join狀態,即非DETACHED狀態傳回值成功結束傳回值為0,否則為錯誤編碼 說明類似於waitpid()
函數原型int pthread_detach(pthread_t thread) 功能執行該函數後線程處於DETACHED狀態處於該狀態的線程結束後自動釋放記憶體資源,不能被pthread_join()同步說明當線程被分離時,不能用pthread_join()等待其終止狀態為避免記憶體流失,線程終止要麼處於分離狀態,要麼處於同步狀態
功能描述
用戶端
使用線程向伺服器發送從標準輸入得到的字元
在主線程中將從伺服器端返回的字元顯示到標準輸出
伺服器端
將用戶端發來的資料原樣返回給用戶端,每一個客戶在伺服器上對應一個線程
Linux - 多線程編程