Linux之執行緒(1)

2021-09-22 14:12:37 字數 3488 閱讀 4133

今天講下linux執行緒這塊的知識,我想很多人應該都知道多執行緒的重要性,現在多執行緒被運用在專案中的次數越來越多,而且面試中多執行緒也是必問的,所以要引起我們足夠的重視將這塊的知識學紮實。

在說執行緒之前我們不得不提到程序,從使用者角度來說:程序是執行中的程式;作業系統角度來說:程序是作業系統對執行中程式的描述資訊–程序描述符–pcb。

執行緒:在乙個程式裡的乙個執行路線

或者說是:執行緒是乙個程序內部的控制序列

而在linux中沒有為執行緒設計乙個tcb來控制線程執行,而是以程序的pcb來模擬實現執行緒,也就是說linux下pcb實際是乙個執行緒,執行緒是程序pcb的模擬實現,因此linux的執行緒也叫做輕量級程序(在linux系統中,在cpu眼中看到的pcb都要比傳統的程序更輕量級),這也就是為什麼linux下多提到的是執行緒,linux下程序實際是乙個執行緒組—當中包含乙個/多個執行緒。

因為cpu排程程式執行是排程pcb,因此執行緒是cpu排程的基本單位。

因為乙個程式執行起來就會分配大量的資源給執行緒組,因此程序是資源分配的基本單位。

同乙個程序的執行緒之間獨有的資料:

棧暫存器

errno

訊號頻閉字

執行緒識別符號

同乙個程序的執行緒之間共享的資料:

資料段,**段

檔案描述符表

訊號的處理方式

工作路徑

使用者id,組id

posix執行緒庫

想使用以下函式必須引入標頭檔案

鏈結這些執行緒函式庫時要使用編譯器命令的「-lpthread」選項

1.執行緒建立

int pthread_create(pthread_t *thread, const pthread_attr_t *attr,

void *(*start_routine) (void *), void *arg);

thread:用於獲取新建立的執行緒id

attr:執行緒屬性,通常是置null

start_routine: 執行緒的入口函式

arg:傳遞給執行緒的引數

返回值:0 失敗:!0

2.執行緒終止

void pthread_exit(void *retval)

retval:用於獲取執行緒退出的返回值

int pthread_cancel(pthread_t thread)

取消乙個指定執行緒,屬於被動推出

thread:指定執行緒的id

主線程退出,程序並不會

3.執行緒等待

int pthread_join(pthread_ pthread,void **retval);

等待乙個執行緒退出

前提:這個被等待的執行緒必須是joinable狀態的

thread:指定執行緒id

retval:用於獲取執行緒退出原因

返回值:0 失敗:!0

4.執行緒分離

int pthread_detach(pthread_t thread);

分離乙個執行緒(設定執行緒的屬性從joinable->detach),執行緒退出後系統將自動**資源,被分離的執行緒無法被等待,若是非要用pthread_join則會直接報錯返回。

thread:指定分離的執行緒id

返回值:0 失敗:!0

執行緒預設的屬性是joinable

程序pid: getpid()

執行緒tid: pthread_self() //程序內唯一,但是在不同程序則不唯一。

執行緒pid: syscall(sys_gettid) //系統內是唯一的(標頭檔案為)

下面通過乙個程式來看三者的區別:

1 #include

2 #include

3 #include

4 #include56

void

*pth_start

(void

* arg)712

return

null;13

}1415int

main()

1624

else

27while(1

)30return0;

31}

執行結果如下:

第一行結果是主線程輸出的,後面那行是新執行緒輸出的,可以看到,pid值是一樣的,因為同屬於乙個程序,所以getpid()值是一樣的,syscall()的值兩個執行緒是不一樣的,而主線程的syscall()和程序的pid值一樣,這是因為主線程的pid和執行緒組的pid值一樣,因此也就和程序的pid值一樣了,前面的兩個pid是在使用者態層面來說的,而後面這個pthred_self()是從核心態角度來說的,也是唯一表示執行緒的id值,pthread_create函式第乙個引數指向乙個虛擬記憶體單元,該記憶體單元的位址即為新建立執行緒的執行緒id,屬於 nptl執行緒庫的範疇。執行緒庫的後續操作,就是根據該執行緒id來操作執行緒的。

為什麼syscall()和pthread_self()都求的是執行緒id為什麼會不一樣呢?

因為執行緒庫實際由兩部分組成:核心的執行緒支援+使用者態的庫支援(glibc), linux早期核心不支援執行緒的時候glibc就在庫中(使用者態)以纖程(即使用者態執行緒)的方式支援多執行緒了,posix thread只要求了使用者程式設計的呼叫介面對核心介面沒有要求。

linux上的執行緒實現就是在核心支援的基礎上以posix thread的方式對外封裝了介面,所以才會有兩個id的問題。

優點:

1)建立乙個新執行緒的代價要比建立乙個新程序小得多

2)與程序之間的切換相比,執行緒之間的切換需要作業系統做的工作要少的多

3)執行緒占用的資源要比程序少很多

4)能充分利用多處理器的可並行數量

5)計算密集型應用,為了能在多處理器系統上執行,將計算分解到多個執行緒中實現

6)i/o密集型應用,為了提高效能,將i/o操作重疊。執行緒可以同時等待不同的i/o操作。

缺點:

效能損失

乙個很少被外部事件阻塞的計算密集型執行緒往往無法與共它執行緒共享同乙個處理器。如果計算密集型 執行緒的數量比可用的處理器多,那麼可能會有較大的效能損失,這裡的效能損失指

的是增加了額外的 同步和排程開銷,而可用的資源不變。

健壯性降低

編寫多執行緒需要更全面更深入的考慮,在乙個多執行緒程式裡,因時間分配上的細微偏差或者因共享了 不該共享的變數而造成不良影響的可能性是很大的,換句話說執行緒之間是缺乏保護的。

缺乏訪問控制

程序是訪問控制的基本粒度,在乙個執行緒中呼叫某些os函式會對整個程序造成影響。

程式設計難度提高

編寫與除錯乙個多執行緒程式比單執行緒程式困難得多。

上面多次提到執行緒導致的安全問題,下節我將會講解執行緒安全以及例項!

Linux 執行緒 1 執行緒概述

程式是應用程式作為乙個靜態檔案儲存在計算機系統的硬碟等儲存空間中,而程序則是處於動態條件下由作業系統維護的系統資源管理實體,也就是程式的動態執行過程。執行緒按照排程者可分為使用者級執行緒和核心級執行緒。使用者級執行緒 主要解決上下文切換問題,它的排程演算法和排程過程全部由使用者自行決定,執行不需要核...

Linux之執行緒

一 執行緒標識 每個執行緒有乙個執行緒id。程序id在整個系統中是唯一的,但執行緒id不同,執行緒id只有在它所屬的程序環境中有效。執行緒id用pthread t資料型別來表示,可以用乙個結構來代表pthread t資料型別。include int pthread equal pthread t t...

Linux之執行緒

不同程序之間切換,系統開銷很大,為了提高效率很多作業系統 windows和linux 都引入了輕量級程序lwp,即執行緒。因為同一程序下的執行緒共享相同的位址空間,所以 同一程序下的 執行緒之間切換系統開銷小效率高。在linux下程式設計,不嚴格區分程序與執行緒,將它們都視為任務,用結構體task ...