Ⅰ linux線程可以創建線程嗎
創建線程一般都是在主線程裡面創建,因為在主線程裡面能夠對線程進行管理控制,而且還有很重要的一點,就是Linux編程中使用線程的好處是可以共享變數,這在主線程的main函數裡面更加方便,所以沒有在線程中再創建線程的用法。既然想在線程中再創建線程,為何不用fork復制進程呢,Linux的進程開銷是非常小的。
Ⅱ linux怎麼創建多線程
線程是「進程」中某個單一順序的控制流。也被稱為輕量進程。在POSIX線程中,線程體是一個函數。用pthread_create函數來啟動這個線程。用pthread_join函數來等待線程結束。在linux中可以通過posix實現
Ⅲ linux線程的創建、退出、等待、取消、分離
返回值:成功:0,錯誤:出錯編號。
pthread不是Linux系統默認的庫而是POSIX線程庫。在Linux中將其作為一個庫來使用,因此編譯時需要加上-pthread以顯式鏈接該庫
返回線程ID
線程標識符在進程中是唯一的,即分別屬於兩不同進程的兩個線程可能有相同的線程標識符
retval:返回信息
參數表:
thread: 要等待的線程的pid
retval:用來存儲被等待線程的返回值
返回0:成功;返回錯誤號:失敗
主線程阻塞自己,等待子線程結束,然後回收子線程資源
可以設置線程能否被取消和取消後是否立即執行
參數表
state:PTHREAD_CANCEL_DISABLE或者PTHREAD_CANCEL_ENABLE
oldstate:指針類型,上一次取消狀態的指針,可設NULL
type:PTHREAD_CANCEL_ASYNCHRONOUS立即取消
PTHREAD_CANCEL_DEFERRED等待事件(如pthread_join時)才取消
在任何一個時間點上,線程是可結合的(joinable),或者是分離的(detached)。一個可結合的線程能夠被其他線程收回其資源和殺死,只有當pthread_join()函數返回時,創建的線程才算終止,才能釋放自己佔用的系統資源;在被其他線程回收之前,它的存儲器資源(如棧)是不釋放的。相反,一個分離的線程是不能被其他線程回收或殺死的,它的存儲器資源在它終止時由系統自動釋放。 因此為了避免內存泄漏,所有線程的終止,要麼已設為DETACHED,要麼就需要使用pthread_join()來回收
返回0成功,錯誤號失敗
分離後不可以再合並。該操作不可逆
綜合以上要想讓子線程總能完整執行(不會中途退出),
註:很多地方參照了黃茹老師主編的《Linux環境高級程序設計》
Ⅳ linux進程、線程及調度演算法(三)
調度策略值得是大家都在ready時,並且CPU已經被調度時,決定誰來運行,誰來被調度。
兩者之間有一定矛盾。
響應的優化,意味著高優先順序會搶占優先順序,會花時間在上下文切換,會影響吞吐。
上下文切換的時間是很短的,幾微妙就能搞定。上下文切換本身對吞吐並多大影響, 重要的是,切換後引起的cpu 的 cache miss.
每次切換APP, 數據都要重新load一次。
Linux 會盡可能的在響應與吞吐之間尋找平衡。比如在編譯linux的時候,會讓你選擇 kernal features -> Preemption model.
搶占模型會影響linux的調度演算法。
所以 ARM 的架構都是big+LITTLE, 一個很猛CPU+ 多個 性能較差的 CPU, 那麼可以把I/O型任務的調度 放在 LITTLE CPU上。需要計算的放在big上。
早期2.6 內核將優先順序劃分了 0-139 bit的優先順序。數值越低,優先順序越高。0-99優先順序 都是 RT(即時響應)的 ,100-139都是非RT的,即normal。
調度的時候 看哪個bitmap 中的 優先順序上有任務ready。可能多個任務哦。
在普通優先順序線程調度中,高優先順序並不代表對低優先順序的絕對優勢。會在不同優先順序進行輪轉。
100 就是比101高,101也會比102高,但100 不會堵著101。
眾屌絲進程在輪轉時,優先順序高的:
初始設置nice值為0,linux 會探測 你是喜歡睡眠,還是幹活。越喜歡睡,linux 越獎勵你,優先順序上升(nice值減少)。越喜歡幹活,優先順序下降(nice值增加)。所以一個進程在linux中,干著干著 優先順序越低,睡著睡著 優先順序越高。
後期linux補丁中
紅黑樹,數據結構, 左邊節點小於右邊節點
同時兼顧了 CPU/IO 和 nice。
數值代表著 進程運行到目前為止的virtual runtime 時間。
(pyhsical runtime) / weight * 1024(系數)。
優先調度 節點值(vruntime)最小的線程。權重weight 其實有nice 來控制。
一個線程一旦被調度到,則物理運行時間增加,vruntime增加,往左邊走。
weight的增加,也導致vruntime減小,往右邊走。
總之 CFS讓線程 從左滾到右,從右滾到左。即照顧了I/O(喜歡睡,分子小) 也 照顧了 nice值低(分母高).所以 由喜歡睡,nice值又低的線程,最容易被調度到。
自動調整,無需向nice一樣做出獎勵懲罰動作,個人理解權重其實相當於nice
但是 此時 來一個 0-99的線程,進行RT調度,都可以瞬間秒殺你!因為人家不是普通的,是RT的!
一個多線程的進程中,每個線程的調度的策略 如 fifo rr normal, 都可以不同。每一個的優先順序都可以不一樣。
實驗舉例, 創建2個線程,同時開2個:
運行2次,創建兩個進程
sudo renice -n -5(nice -5級別) -g(global), 會明顯看到 一個進程的CPU佔用率是另一個的 3倍。
為什麼cpu都已經達到200%,為什麼系統不覺得卡呢?因為,我們的線程在未設置優先順序時,是normal調度模式,且是 CPU消耗型 調度級別其實不高。
利用chrt工具,可以將進程 調整為 50 從normal的調度策略 升為RT (fifo)級別的調度策略,會出現:
chrt , nice renice 的調度策略 都是以線程為單位的,以上 設置的將進程下的所有線程進行設置nice值
線程是調度單位,進程不是,進程是資源封裝單位!
兩個同樣死循環的normal優先順序線程,其中一個nice值降低,該線程的CPU 利用率就會比另一個CPU的利用率高。
Ⅳ linux 可以在線程中再創建線程嗎
1、windows里的進程/線程是繼承自OS/2的。在windows里,"進程"是指一個程序,而"線程"是一個"進程"里的一個執行"線索"。從核心上講,windows的多進程與Linux並無多大的區別,在windows里的線程才相當於Linux的進程,是一個實際正在執行的代碼。但是,windows里同一個進程里各個線程之間是共享數據段的。這才是與Linux的進程最大的不同。2、在windows下,使用CreateThread函數創建線程,與Linux下創建進程同,windows線程不是從創建處開始運行的,而是由CreateThread指定一個函數,線程就從那個函數處開始運行。此程序同前面的UNIX程序一樣,由兩個線程各列印1000條信息。threadID是子線程的線程號,另外,全局變數g是子線程與父線程共享的,這就是與Linux最大的不同之處。大家可以看出,windows的進程/線程要比Linux復雜,在Linux要實現類似windows的線程並不難,只要fork以後,讓子進程調用ThreadProc函數,並且為全局變數開設共享數據區就行了,但在windows下就無法實現類似fork的功能了。所以現在windows下的C語言編譯器所提供的庫函數雖然已經能兼容大多數Linux/UNIX的庫函數,但卻仍無法實現fork。3、對於多任務系統,共享數據區是必要的,但也是一個容易引起混亂的問題,windows下,一個程序員很容易忘記線程之間的數據是共享的這一情況,一個線程修改過一個變數後,另一個線程卻又修改了它,結果引起程序出問題。但在Linux下,由於變數本來並不共享,而由程序員來顯式地指定要共享的數據,使程序變得更清晰與安全。
Ⅵ 「圖文結合」Linux 進程、線程、文件描述符的底層原理
開發十年經驗總結,阿里架構師的手寫Spring boot原理實踐文檔
阿里架構師的這份:Redis核心原理與應用實踐,帶你手撕Redis
Tomcat結構原理詳解
說到進程,恐怕面試中最常見的問題就是線程和進程的關系了,那麼先說一下答案: 在 Linux 系統中,進程和線程幾乎沒有區別 。
Linux 中的進程其實就是一個數據結構,順帶可以理解文件描述符、重定向、管道命令的底層工作原理,最後我們從操作系統的角度看看為什麼說線程和進程基本沒有區別。
首先,抽象地來說,我們的計算機就是這個東西:
這個大的矩形表示計算機的 內存空間 ,其中的小矩形代表 進程 ,左下角的圓形表示 磁碟 ,右下角的圖形表示一些 輸入輸出設備 ,比如滑鼠鍵盤顯示器等等。另外,注意到內存空間被劃分為了兩塊,上半部分表示 用戶空間 ,下半部分表示 內核空間 。
用戶空間裝著用戶進程需要使用的資源,比如你在程序代碼里開一個數組,這個數組肯定存在用戶空間;內核空間存放內核進程需要載入的系統資源,這一些資源一般是不允許用戶訪問的。但是注意有的用戶進程會共享一些內核空間的資源,比如一些動態鏈接庫等等。
我們用 C 語言寫一個 hello 程序,編譯後得到一個可執行文件,在命令行運行就可以列印出一句 hello world,然後程序退出。在操作系統層面,就是新建了一個進程,這個進程將我們編譯出來的可執行文件讀入內存空間,然後執行,最後退出。
你編譯好的那個可執行程序只是一個文件,不是進程,可執行文件必須要載入內存,包裝成一個進程才能真正跑起來。進程是要依靠操作系統創建的,每個進程都有它的固有屬性,比如進程號(PID)、進程狀態、打開的文件等等,進程創建好之後,讀入你的程序,你的程序才被系統執行。
那麼,操作系統是如何創建進程的呢? 對於操作系統,進程就是一個數據結構 ,我們直接來看 Linux 的源碼:
task_struct 就是 Linux 內核對於一個進程的描述,也可以稱為「進程描述符」。源碼比較復雜,我這里就截取了一小部分比較常見的。
我們主要聊聊 mm 指針和 files 指針。 mm 指向的是進程的虛擬內存,也就是載入資源和可執行文件的地方; files 指針指向一個數組,這個數組里裝著所有該進程打開的文件的指針。
先說 files ,它是一個文件指針數組。一般來說,一個進程會從 files[0] 讀取輸入,將輸出寫入 files[1] ,將錯誤信息寫入 files[2] 。
舉個例子,以我們的角度 C 語言的 printf 函數是向命令行列印字元,但是從進程的角度來看,就是向 files[1] 寫入數據;同理, scanf 函數就是進程試圖從 files[0] 這個文件中讀取數據。
每個進程被創建時, files 的前三位被填入默認值,分別指向標准輸入流、標准輸出流、標准錯誤流。我們常說的「文件描述符」就是指這個文件指針數組的索引 ,所以程序的文件描述符默認情況下 0 是輸入,1 是輸出,2 是錯誤。
我們可以重新畫一幅圖:
對於一般的計算機,輸入流是鍵盤,輸出流是顯示器,錯誤流也是顯示器,所以現在這個進程和內核連了三根線。因為硬體都是由內核管理的,我們的進程需要通過「系統調用」讓內核進程訪問硬體資源。
PS:不要忘了,Linux 中一切都被抽象成文件,設備也是文件,可以進行讀和寫。
如果我們寫的程序需要其他資源,比如打開一個文件進行讀寫,這也很簡單,進行系統調用,讓內核把文件打開,這個文件就會被放到 files 的第 4 個位置,對應文件描述符 3:
明白了這個原理, 輸入重定向 就很好理解了,程序想讀取數據的時候就會去 files[0] 讀取,所以我們只要把 files[0] 指向一個文件,那麼程序就會從這個文件中讀取數據,而不是從鍵盤:
同理, 輸出重定向 就是把 files[1] 指向一個文件,那麼程序的輸出就不會寫入到顯示器,而是寫入到這個文件中:
錯誤重定向也是一樣的,就不再贅述。
管道符其實也是異曲同工,把一個進程的輸出流和另一個進程的輸入流接起一條「管道」,數據就在其中傳遞,不得不說這種設計思想真的很巧妙:
到這里,你可能也看出「Linux 中一切皆文件」設計思路的高明了,不管是設備、另一個進程、socket 套接字還是真正的文件,全部都可以讀寫,統一裝進一個簡單的 files 數組,進程通過簡單的文件描述符訪問相應資源,具體細節交於操作系統,有效解耦,優美高效。
首先要明確的是,多進程和多線程都是並發,都可以提高處理器的利用效率,所以現在的關鍵是,多線程和多進程有啥區別。
為什麼說 Linux 中線程和進程基本沒有區別呢,因為從 Linux 內核的角度來看,並沒有把線程和進程區別對待。
我們知道系統調用 fork() 可以新建一個子進程,函數 pthread() 可以新建一個線程。 但無論線程還是進程,都是用 task_struct 結構表示的,唯一的區別就是共享的數據區域不同 。
換句話說,線程看起來跟進程沒有區別,只是線程的某些數據區域和其父進程是共享的,而子進程是拷貝副本,而不是共享。就比如說, mm 結構和 files 結構在線程中都是共享的,我畫兩張圖你就明白了:
所以說,我們的多線程程序要利用鎖機制,避免多個線程同時往同一區域寫入數據,否則可能造成數據錯亂。
那麼你可能問, 既然進程和線程差不多,而且多進程數據不共享,即不存在數據錯亂的問題,為什麼多線程的使用比多進程普遍得多呢 ?
因為現實中數據共享的並發更普遍呀,比如十個人同時從一個賬戶取十元,我們希望的是這個共享賬戶的余額正確減少一百元,而不是希望每人獲得一個賬戶的拷貝,每個拷貝賬戶減少十元。
當然,必須要說明的是, 只有 Linux 系統將線程看做共享數據的進程 ,不對其做特殊看待 ,其他的很多操作系統是對線程和進程區別對待的,線程有其特有的數據結構,我個人認為不如 Linux 的這種設計簡潔,增加了系統的復雜度。
在 Linux 中新建線程和進程的效率都是很高的,對於新建進程時內存區域拷貝的問題,Linux 採用了 -on-write 的策略優化,也就是並不真正復制父進程的內存空間,而是等到需要寫操作時才去復制。 所以 Linux 中新建進程和新建線程都是很迅速的 。
Ⅶ linux進程、線程及調度演算法(二)
執行一個 ,但是只要任何修改,都造成分裂如,修改了chroot,寫memory,mmap,sigaction 等。
p1 是一個 task_struct, p2 也是一個 task_struct. linux內核的調度器只認得task_struck (不管你是進程還是線程), 對其進行調度。
p2 的task_struck 被創建出來後,也有一份自己的資源。但是這些資源會短暫的與p1 相同。
進程是區分資源的單位,你的資源是我的資源,那從概念上將就不叫進程。
其他資源都好分配,唯一比較難的是內存資源的重新分配。
非常簡單的程序,但是可以充分說明 COW。
結果:10 -> 20 -> 10
COW 是嚴重依賴於CPU中的MMU。CPU如果沒有 MMU,fork 是不能工作的。
在沒有mmu的CPU中,不可能執行COW 的,所以只有vfork
vfork與fork相比的不同
P2沒有自己的 task_struct, 也就是說P1 的內存資源 就是 P2的內存資源。
結果 10,20,20
vfork:
vfork 執行上述流程,P2也只是指向了P1的mm,那麼將這個vfork 放大,其餘的也全部clone,共同指向P1,那麼就是線程的屬性了。
phtread_create -> Clone()
P1 P2 在內核中都是 task_struct. 都可以被調度。共享資源可調度,即線程。 這就是線程為什麼也叫做輕量級進程
不需要太糾結線程和進程的區別。
4651 : TGID
4652, 4653 tid 內核中 task_struct 真正的pid
linux 總是白發人 送 黑發人。如果父進程在子進程推出前掛掉了。那麼子進程應該怎麼辦?
p3 -> init, p5 -> subreaper
每一個孤兒都會找最近的火葬場
可以設置進程的屬性,將其變為subreaper,會像1號進程那樣收養孤兒進程。
linux的進程睡眠依靠等待隊列,這樣的機制類似與涉及模式中的訂閱與發布。
睡眠,分兩種
每一個進程都是創建出來的,那麼第一個進程是誰創建的呢?
init 進程是被linux的 0 進程 創建出來的。開機創建。
父進程就是 0 號進程,但在pstree,是看不到0進程的。因為0進程創建子進程後,就退化成了idle進程。
idle進程是 linux內核里,特殊調度類。 所有進程都睡眠停止 ,則調度idle進程,進入到 wait for interrupte 等中斷。此時 cpu及其省電,除非來一個中斷,才能再次被喚醒。
喚醒後的任何進程,從調度的角度上說,都比idle進程地位高。idle是調度級別最最低的進程。
0 進程 一跑,則進入等中斷。一旦其他進程被喚醒,就輪不到 0進程了。
所有進程都睡了,0就上來,則cpu需要進入省電模式
Ⅷ Linux中進程和線程的對比與區別
線程和進程是另一對有意義的概念,主要區別和聯系如下:
進程是操作系統進行資源分配的基本單位,擁有完整的進程空間。進行系統資源分配的時候,除了CPU資源之外,不會給線程分配獨立的資源,線程所需要的資源需要共享。
線程是進程的一部分,如果沒有進行顯示的線程分配,可以認為進程是單線程的;如果進程中建立了線程,則可認為系統是多線程的。
多線程和多進程是兩種不同的概念。多線程與多進程有不同的資源共享方式。
進程有進程式控制制塊PCB,系統通過PCB對進程進行調度。進程有線程式控制制塊TCP,但TCB所表示的狀態比PCB要少的多。
Ⅸ linux 下 進程和線程的區別
線程是指進程內的一個執行單元,也是進程內的可調度實體.
與進程的區別:
(1)地址空間:進程內的一個執行單元;進程至少有一個線程;它們共享進程的地址空間;而進程有自己獨立的地址空間;
(2)資源擁有:進程是資源分配和擁有的單位,同一個進程內的線程共享進程的資源
(3)線程是處理器調度的基本單位,但進程不是.
4)二者均可並發執行.
進程和線程都是由操作系統所體會的程序運行的基本單元,系統利用該基本單元實現系統對應用的並發性。進程是系統進行資源分配和調度的一個獨立單位。線程是進程的一個實體,是CPU調度和分派的基本單位,線程自己基本上不擁有系統資源,只擁有一點在運行中必不可少的資源(如程序計數器,一組寄存器和棧),但是它可與同屬一個進程的其他的線程共享進程所擁有的全部資源。一個線程可以創建和撤銷另一個線程,同一個進程中的多個線程之間可以並發執行。
2.進程和應用程序的區別?
進程與應用程序的區別在於應用程序作為一個靜態文件存儲在計算機系統的硬碟等存儲空間中,而進程則是處於動態條件下由操作系統維護的系統資源管理實體。
C、C++、Java等語言編寫的源程序經相應的編譯器編譯成可執行文件後,提交給計算機處理器運行。這時,處在可執行狀態中的應用程序稱為進程。從用戶角度來看,進程是應用程序的一個執行過程。從操作系統核心角度來看,進程代表的是操作系統分配的內存、CPU時間片等資源的基本單位,是為正在運行的程序提供的運行環境。進程與應用程序的區別在於應用程序作為一個靜態文件存儲在計算機系統的硬碟等存儲空間中,而進程則是處於動態條件下由操作系統維護的系統資源管理實體。多任務環境下應用程序進程的主要特點包括: ●進程在執行過程中有內存單元的初始入口點,並且進程存活過程中始終擁有獨立的內存地址空間; ●進程的生存期狀態包括創建、就緒、運行、阻塞和死亡等類型; ●從應用程序進程在執行過程中向CPU發出的運行指令形式不同,可以將進程的狀態分為用戶態和核心態。處於用戶態下的進程執行的是應用程序指令、處於核心態下的應用程序進程執行的是操作系統指令
3.進程與Java線程的區別
應用程序在執行過程中存在一個內存空間的初始入口點地址、一個程序執行過程中的代碼執行序列以及用於標識進程結束的內存出口點地址,在進程執行過程中的每一時間點均有唯一的處理器指令與內存單元地址相對應。
Java語言中定義的線程(Thread)同樣包括一個內存入口點地址、一個出口點地址以及能夠順序執行的代碼序列。但是進程與線程的重要區別在於線程不能夠單獨執行,它必須運行在處於活動狀態的應用程序進程中,因此可以定義線程是程序內部的具有並發性的順序代碼流。 Unix操作系統和Microsoft Windows操作系統支持多用戶、多進程的並發執行,而Java語言支持應用程序進程內部的多個執行線程的並發執行。多線程的意義在於一個應用程序的多個邏輯單元可以並發地執行。但是多線程並不意味著多個用戶進程在執行,操作系統也不把每個線程作為獨立的進程來分配獨立的系統資源。進程可以創建其子進程,子進程與父進程擁有不同的可執行代碼和數據內存空間。而在用於代表應用程序的進程中多個線程共享數據內存空間,但保持每個線程擁有獨立的執行堆棧和程序執行上下文(Context)。
需要注意的是:在應用程序中使用多線程不會增加 CPU 的數據處理能力。只有在多CPU 的計算機或者在網路計算體系結構下,將Java程序劃分為多個並發執行線程後,同時啟動多個線程運行,使不同的線程運行在基於不同處理器的Java虛擬機中,才能提高應用程序的執行效率。 另外,如果應用程序必須等待網路連接或資料庫連接等數據吞吐速度相對較慢的資源時,多線程應用程序是非常有利的。基於Internet的應用程序有必要是多線程類型的,例如,當開發要支持大量客戶機的伺服器端應用程序時,可以將應用程序創建成多線程形式來響應客戶端的連接請求,使每個連接用戶獨佔一個客戶端連接線程。這樣,用戶感覺伺服器只為連接用戶自己服務,從而縮短了伺服器的客戶端響應時間。 三、Java語言的多線程程序設計方法