多線程(thread)
?? 操作系統支持多進程,進程內部使用多線程。
?? 進程是 重量級的,擁有自己 獨立的內存空間。
?? 線程是 輕量級的,不需要擁有自己 獨立的內存空間,線程的內存空間:1 共享進程的內存空間 2 每個線程擁有一個與其他線程獨立的棧。
?? 因此,遇到大量的并行,多半使用多線程技術。
? 一般來說,網絡編程 離不開多線程。
?? 進程中支持多線程,但必須有一個主線程(main)。
?? 多個線程之間互相獨立,但也互相影響(共享進程的內存)。
?? 主線程和其他線程也是獨立的,但有特殊性:
?????? 1 其他線程都是通過主線程 直接/間接 啟動
?????? 2 主線程結束,進程結束->所有線程都結束
? 線程并行的原理和機制
???? 傳統上說,代碼有三種運行的方式:
?????????? 順序執行/循環執行/選擇執行
?? 代碼的并行:
??? 真正意義的并行 是不存在的,我們看到的并行都是針對時間段的。
??? CPU把自己工作時間分成 極小的CPU時間片,每個線程都會拿到CPU時間片,CPU時間片的持有者可以運行CPU(CPU時間片的大小決定運行時間)。當我們感知(過了時間段)的時候,多個線程都運行了N個時間片,因此感覺上是并行。
??? UC中對于線程的開發已經做了一系列的函數,放入libpthread.so中。因此 連接時,需要加-lpthread,l可以省略,所有線程的函數 在連接時必須加 -pthread。
??? 使用pthread.h頭文件,都以pthread_ 開頭。
??? 創建線程函數:
??? int pthread_create(pthread_t* id,? pthread_attr_t* attr, void*(*f)(void*), void* p )
??????? id 用于存儲 線程id
??????? attr 傳入屬性,一般給NULL,使用默認屬性即可
??????? f 是函數指針,線程執行的代碼放入f函數
??????? p 是f的參數,可以在創建線程時傳入
?? 返回:
????? 成功返回0,失敗 返回 錯誤編號。線程的錯誤碼不能使用errno,而是 由函數直接返回。
?? 注:函數f不需要顯式調用,create線程后自動執行f的代碼,同時 p 做f的參數。
?? 關于函數的返回:
?? 1 不能返回指向局部變量的指針
?? 2 不要直接返回 復合類型的局部變量
?? 3 只有指向 static 局部變量的指針可以返回
? 線程 用 pthread_join 取返回值。
?? 線程有分離和非分離狀態,默認是 非分離狀態,支持pthread_join,并且資源在join函數結束之后才釋放,而不是 線程結束馬上釋放。??????
?? 分離狀態 線程結束馬上釋放資源,處于分離狀態的線程join沒作用。(了解)
?? pthread_detach(id);//可以把線程id設置為分離
? 線程同步:
?? 線程 共享進程的系統資源(全部、堆、文件),如果一個線程改變了其中的某項,就會影響其他的線程。因此多個線程在操作共享資源時,使用 線程同步 技術防止數據出現不一致,不完整的問題。
?? 互斥(mutex)就是一種線程同步的技術。能解決同步問題,但 會大幅降低多線程的效率,所以不要濫用
? 互斥的使用步驟:
?? 1 定義一個互斥
???? pthread_mutex_t lock;
?? 2 初始化 互斥,兩種方式:
???? lock = PTHREAD_MUTEX_INITIALIZER;
???? pthread_mutex_init(&lock);
?? 3 加鎖,取互斥(只有一個可以取得,其他被鎖定)
???? pthread_mutex_lock(&lock);
?? 4 執行自己的代碼
?? 5 釋放鎖,還互斥(激活被鎖定的線程)
???? pthread_mutex_unlock(&lock);
?? 6 銷毀互斥(不能再次使用)
???? pthread_mutex_destroy(&lock);
?? 在使用互斥時,一定要避免死鎖,因此沒有及時釋放互斥導致其他所有線程 鎖死。
?? 互斥是線程同步的特有技術,而信號量是可以控制進程和線程的技術。(與IPC的信號量集不是一個技術)
信號量是一個計數器,當 計數為1 時,和互斥效果一致。信號量的使用步驟:
??? 1 定義一個信號量
???? sem_t sem; //不在pthread.h中,在semaphore.h
??? 2 初始化信號量
???? sem_init(&sem,0,int 計數值)
???? 第一個參數是 信號量的指針
???? 第二個參數必須是0,0代表線程,非0代表進程
???? 第三個參數是計數器的初始值
??? 3 獲取一個信號量(計數-1)
???? sem_wait(&sem);
??? 4 執行代碼
??? 5 釋放一個信號量(計數+1)
???? sem_post(&sem);
??? 6 不用了就可以銷毀
???? sem_destroy(&sem);????