linux多線程pthread系列函數詳解
(一)為什么要引入線程
線程技術早在60年代就被提出,但是在80年代才真正使用到操作系統中。傳統UNIX也支持多線程概念,但在一個進程中只允許有一個線程,這樣多線程就意味着多進程。現在多線程技術已經被很多操作系統支持,包含Windows/NT,當然也包含Linux。
我們知道新建立一個進程的代價是非常昂貴的,內核需要分配一個新的地址空間,建立眾多的數據表來維護他的數據段/代碼段等。但是在一個進程中的多個線程,使用相同的地址空間,共享大部分數據,新建立一個線程花費的時間要遠遠小於新建一個進程,而且,線程之間的切換速度也遠遠小於進程的切換速度。
另外一點是通信的快速,進程由於有獨立的地址空間,進程的數據傳遞往往使用通信的方式。而線程共享同一個數據空間,多個線程之間只需要做好數據保護,就可以直接使用數據,避免拷貝。
線程優點總結以下幾個方面:
1)提高程序響應速度。比如按鍵響應這種耗時的操作可以在一個新建立的線程中去做,這樣就不會影響其他的程序執行。
2)改善程序結構,復雜的邏輯可以按照業務拆分出多個線程處理,程序會利於修改與整理。
3)更好的應用於SMP系統,一個進程的多個線程可以分配到不同CPU上面運行。
(二)Pthread
Linux下的多線程遵從POSIX線程接口,簡稱pthread,在pthread庫中提供。
pthread_create():創建一個線程
pthread_exit():退出一個線程
pthread_jion():阻塞當前線程,直到另一個線程執行結束
pthread_attr_init():設置線程是否脫離屬性
pthread_kill():給線程發送kill信號
同步函數:
pthread_mutex_lock():互斥加鎖
pthread_mutex_unlock():互斥鎖解鎖
pthread_cond_init():初始化條件變量
pthread_cond_signal():發送信號喚醒進程
pthread_cond_wait():等待條件變量的特殊事件發生
(三)pthread互斥鎖的實現原理
pthread_create線程的創建:
最初的進程包含程序/資源/執行三部分,程序就是代碼,資源主要包含系統層面上的內存/IO/信號資源等,而執行就是指執行上下文,包含代碼對CPU的使用。后來設計者逐漸修正了進程的概念,允許資源不被進程嚴格獨占,允許某些進程共享一部分資源比如信號/文件/數據內存/甚至代碼。這就逐漸發展出輕量進程的概念,Linux2.4就已經實現了輕量進程的概念,通過調用clone的系統調用,設置不同的參數來設置是普通進程還是輕量級進程。clone最終調用do_fork函數,不同的clone_flag使do_fork有不同的行為:
LinuxThread使用(CLONE_VM|CLONE_FS|CLONE_FILES|CLONESIGHAND)調用clone函數,表明創建的新進程為共享內存/共享文件系統訪問計數/共享文件描述符表/共享信號處理方式的意思。
LinuxThreads就是實現基於核心輕量級進程的“一對一”線程模型,一個線程實體對應一個核心輕量級進程,而線程之間的管理在核外函數庫中實現。“一對一”模型的好處是線程的調度由核心完成,而其他諸如線程取消/線程間同步等工作都是在核心外的線程庫中做的,在LinuxThreads中,專門為每個進程構造了一個管理線程,負責處理線程相關的管理工作。
pthread_mutex_lock互斥鎖原理:
pthread_mutex_lock屬於sleepwaiting類型的鎖。Linux上的mutex互斥鎖都是futex類型的鎖。
futex(fast usermode mutex)快速用戶去互斥鎖的檢查,futex時候由用戶空間的一個對齊的整形變量和附在其上的內核空間的等待隊列構成。這種鎖的思想是,當鎖沒有競爭時,對位於用戶空間的futex的整形變量進程操作(匯編語言調用CPU提供的原子操作來增加或減少它),當鎖有競爭時,則通過內核態調用,將競爭失敗的進程放入等待隊列,並喚醒競爭成功的進程到就緒隊列來是吸納
(四)pthread在項目中的使用
在處理數據流的項目中,DevCapture是抓取視頻流的類,注冊硬件產生的視頻流,一個DevCapture就是繼承一個線程,CRecord/CStreamSend等類將數據處理函數注冊到DevCapture中,由DevCapture的線程執行體調用各個注冊的處理函數。
整個項目的關鍵處理程序在一個進程中,不同通道的流和具體線程的分配我不確定對應的策略。
數據流的發送處理在DevCapture中,沒有經過數據拷貝。
接收是通過系統的協議棧獲取上來的數據,必然由獨立的線程recv,進行數據拼接,並模擬出一個類似DevCapture的ICapture類。
