linux線程用戶
『壹』 linux內核線程kernel thread詳解
Linux內核線程(kernel thread)是內核中的執行流,其設計目的是為了支持多線程並行執行,同時避免因阻塞操作導致的線程暫停。內核線程在內核態下運行,由內核負責調度,每個線程處於阻塞狀態時,不會影響其他線程的執行,因為線程是調度的基本單位。與用戶線程不同,內核線程只能訪問大於PAGE_OFFSET(在傳統x86_32系統上約為3G)的地址空間,這限制了其地址空間的大小。
內核線程由內核自身啟動,它們執行內核任務,如管理資源或響應用戶進程請求。內核線程有兩種類型:一種是直接由內核生成的線程,另一種則是通過特定介面創建的線程。這些線程通常與內核的其他部分並行運行,用於執行特定任務。
在Linux內核中,進程描述符(task_struct)包含與進程地址空間相關的欄位,如mm和active_mm。大多數系統將地址空間分為用戶層部分和內核空間部分。普通用戶進程的mm指向虛擬地址空間的用戶空間部分,而內核線程的mm為NULL,這使得內核可以優化地址轉換處理,避免頻繁切換虛擬地址空間。active_mm用於在內核線程切換時保持舊設置,確保用戶空間部分的內容在需要時可以訪問。
內核線程創建介面經歷了演化,從早期的kernel_create和daemonize介面到更現代的kthread_create和kthread_run介面,這些介面允許內核線程的創建被延遲到工作隊列中,從而簡化了創建過程。一個特殊內核線程kthreadd(在系統初始化時創建)負責定期檢查並執行工作隊列中的任務,從而創建新線程。
內核線程在系統進程中顯示為[]標識,與普通進程區分。它們共享內核地址空間,不具有獨立的地址空間,因此mm指針被設置為NULL。內核線程在內核空間運行,從不切換到用戶空間,且可以被調度和搶占。
創建內核線程的過程經歷了從低效復雜的早期介面到更簡潔的kthread_create和kthread_run介面的演變,這些介面通過將創建操作委託給一個專門的內核線程(如kthreadd)來簡化實現。工作隊列機制進一步優化了內核線程的創建過程,使得系統能夠動態分配線程數量,提高資源利用率。
內核線程通過將任務插入工作隊列中並在適當的時機執行,實現了創建過程的高效管理。kthread_create介面創建線程並將其插入工作隊列,而kthread_run介面則直接喚醒創建的線程開始執行。這些機制不僅簡化了內核線程的創建,還方便了用戶的編程。
內核線程的退出是通過調用do_exit函數或外部進程調用kthread_stop函數來實現的。退出過程中,線程會檢查並處理信號,以確保在退出前釋放資源,避免意外中斷。
總結,Linux內核線程是內核管理資源和執行特定任務的核心組件,它們在內核態下運行,共享內核地址空間,通過高效介面和工作隊列機制簡化了創建過程。在多線程環境中,內核線程提供了強大的並行執行能力,增強了內核的性能和靈活性。
『貳』 通俗易懂的了解——Linux線程模型和線程切換
Linux線程模型和線程切換的通俗理解Linux線程模型:
基本概念:在Linux中,進程是資源分配的基本單位,而線程是CPU調度的基本單位。線程共享進程的資源,但每個線程都有自己的執行路徑。
內核態與用戶態:內核態不區分進程和線程,都使用task_struct結構體保存。用戶態則區分進程和線程,通過不同的系統調用創建。
線程模型類型:
- 一對一:一個用戶線程對應一個內核線程。Linux 2.6默認使用NPTL線程庫,採用此模型。優點在於實現簡單,調度效率高;缺點在於資源消耗相對較大。
- 多對一:多個用戶線程對應同一個內核線程。優點在於資源消耗小;缺點在於線程切換和同步需要用戶空間線程庫處理,效率較低。
- 多對多:m個用戶線程對應n個內核線程。已廢棄的模型,旨在平衡資源消耗和調度效率。
線程切換:
基本概念:線程切換是指CPU從當前執行的線程切換到另一個線程執行的過程。
直接開銷:
- 用戶態與內核態切換:線程切換只能在內核態完成,如果當前用戶處於用戶態,則會引起用戶態與內核態的切換,帶來一定的開銷。
- 上下文切換:切換時需要保存和恢復舊線程的上下文,這是線程切換的主要開銷之一。
- 線程調度演算法:管理線程狀態和等待條件等,如果線程切換頻繁,調度演算法的開銷也不容忽視。
間接開銷:
- 緩存缺失:切換線程後,如果新線程訪問的地址空間與舊線程不相近,可能會引起緩存缺失,影響性能。
- 其他快慢表式結構:如頁表等也可能因線程切換而受到影響。
綜上所述,Linux線程模型主要有一對一、多對一和多對多三種類型,其中一對一模型最為常用。線程切換涉及用戶態與內核態的切換、上下文切換以及線程調度演算法等開銷,同時還可能引起緩存缺失等間接開銷。理解這些概念和開銷有助於優化多線程程序的性能。
『叄』 Linux內核線程kthread簡介【最好的一篇!】
Linux內核線程kthread簡介:
1. 內核線程的基本概念: 定義:內核線程是Linux內核中的獨立執行單元,專門用於處理特定任務。它們由內核自主調度,在內核態運行。 地址空間:內核線程擁有3G以上的地址空間,與用戶線程不同,它們不會影響其他線程的運行。 與用戶進程的區分:內核線程沒有獨立地址空間,mm指針為NULL,僅限於內核空間,可以被調度和搶占。
2. 內核線程的創建與管理: 創建方法:創建內核線程有多種方法,其中通過”kthread_create”和”wake_up_process”配合是一種常見方式,”kthread_run”則是一個便利的封裝,負責線程的創建和啟動。 線程管理:內核中有一個持續運行的線程kthreadd,它負責管理其他內核線程。通過”kthread_create“創建線程後,線程在遇到”kthread_should_stop”或”kthread_stop“時才會結束。 線程名稱:在”kthread_run”中,線程名稱由sprintf格式字元串組成。
3. 內核線程的生命周期: 創建:通過調用”kthread_create“或”kthread_run“創建線程,並設置線程的任務結構和入口函數。 運行:創建成功後,新線程被喚醒並進入內核線程的入口函數,如”kthread“。 結束:通過調用”kthread_stop“結束線程,確保線程在結束前完成相關操作,避免異常。
4. 內核線程的重要性: 效率與穩定性:內核線程的設計確保了操作系統在處理任務時的效率和穩定性。 並發管理:內核線程的創建、調度和退出機制被精心設計,以處理並發問題。 操作系統編程基礎:理解內核線程的工作原理對於操作系統編程至關重要,特別是在處理並發問題和理解內核工作原理方面。
『肆』 Linux用戶進程內核態執行,內核線程的關系問題
1、幾乎所有的程序都要切換到內核態運行再返回用戶態,用中斷完成的,因為在內核下封裝了一些東西,用戶態下只是傳入某些參數後調用內核態下的函數罷了,
2、進程有三態(執行態,就緒態,阻塞態),cpu任何時刻都只有一個進程在執行,so從用戶態切換到內核態時,用戶態下的進程就處於阻塞或就緒態了,至於從用戶態切換到內核態執行哪個函數那就看你在用戶態下執行的是什麼函數了,比如在用戶態下的lseek在內核下就是llseek了,不一樣的。
3、這問題就是linux的內存管理了,這里就得提到三種地址(邏輯地址、線性地址、物理地址),這里我們提到的4G地址是邏輯地址,不是我們實際的物理地址,linux中一個進程用戶佔0-3G對應的內核佔3G-4G部分
說得不是很清楚,這是比較復雜的內容,需要從頭看起,單就這幾個問題是不能搞懂linux的,最好還是系統的學習,不斷的重復
『伍』 Linux用戶線程和內核線程區別
Linux用戶線程與內核線程的主要區別在於它們的實現方式、調度機制和性能開銷。
用戶級線程
用戶級線程的實現完全在用戶空間進行,內核並不直接感知。這種模型的優點包括:調度由應用程序自行管理,開銷較小,線程切換速度快。然而,缺點是開發者需要負責調度,並且資源競爭僅限於進程內。
內核級線程
內核級線程由內核直接管理,操作系統內核能感知每個線程,可以全系統范圍內調度資源。優點在於線程創建和調度由內核處理,性能穩定,但開銷較大,線程切換需進入內核,可能導致性能損失。
用戶線程在不支持內核線程的系統中也能工作,創建成本低且調度靈活,但資源競爭受限於進程。內核線程則提供了更直接的並發控制,但創建和調度成本高。
操作系統通常採用不同的線程模型來平衡性能和資源使用,如一對一或多對多模型,各有優缺點。例如,多對一模型適合用戶空間效率,一對一模型提供更好的並發性,而多對多模型則在一定程度上兼顧兩者。
『陸』 linux下線程屬性常用操作有哪些
LinuxThread的線程機制
LinuxThreads是目前Linux平台上使用最為廣泛的線程庫,由Xavier Leroy ([email protected]) 負責開發完成,並已綁定在GLIBC中發行。它所實現的就是基於核心輕量級進程的"一對一"線程模型,一個線程實體對應一個核心輕量級進程,而線程之間的 管理在核外函數庫中實現。
1.線程描述數據結構及實現限制
LinuxThreads定義了一個struct _pthread_descr_struct數據結構來描述線程,並使用全局數組變數 __pthread_handles來描述和引用進程所轄線程。在__pthread_handles中的前兩項,LinuxThreads定義了兩個全 局的系統線程:__pthread_initial_thread和__pthread_manager_thread,並用 __pthread_main_thread表徵__pthread_manager_thread的父線程(初始為 __pthread_initial_thread)。
struct _pthread_descr_struct是一個雙環鏈表結構,__pthread_manager_thread所在的鏈表僅包括它 一個元素,實際上,__pthread_manager_thread是一個特殊線程,LinuxThreads僅使用了其中的errno、p_pid、 p_priority等三個域。而__pthread_main_thread所在的鏈則將進程中所有用戶線程串在了一起。經過一系列 pthread_create()之後形成的__pthread_handles數組將如下圖所示:
圖2 __pthread_handles數組結構
新創建的線程將首先在__pthread_handles數組中占據一項,然後通過數據結構中的鏈指針連入以__pthread_main_thread為首指針的鏈表中。這個鏈表的使用在介紹線程的創建和釋放的時候將提到。
LinuxThreads遵循POSIX1003.1c標准,其中對線程庫的實現進行了一些范圍限制,比如進程最大線程數,線程私有數據區大小等等。在 LinuxThreads的實現中,基本遵循這些限制,但也進行了一定的改動,改動的趨勢是放鬆或者說擴大這些限制,使編程更加方便。這些限定宏主要集中 在sysdeps/unix/sysv/linux/bits/local_lim.h(不同平台使用的文件位置不同)中,包括如下幾個:
每進程的私有數據key數,POSIX定義_POSIX_THREAD_KEYS_MAX為128,LinuxThreads使用 PTHREAD_KEYS_MAX,1024;私有數據釋放時允許執行的操作數,LinuxThreads與POSIX一致,定義 PTHREAD_DESTRUCTOR_ITERATIONS為4;每進程的線程數,POSIX定義為64,LinuxThreads增大到1024 (PTHREAD_THREADS_MAX);線程運行棧最小空間大小,POSIX未指定,LinuxThreads使用 PTHREAD_STACK_MIN,16384(位元組)。
2.管理線程
"一對一"模型的好處之一是線程的調度由核心完成了,而其他諸如線程取消、線程間的同步等工作,都是在核外線程庫中完成的。在LinuxThreads 中,專門為每一個進程構造了一個管理線程,負責處理線程相關的管理工作。當進程第一次調用pthread_create()創建一個線程的時候就會創建 (__clone())並啟動管理線程。
在一個進程空間內,管理線程與其他線程之間通過一對"管理管道(manager_pipe[2])"來通訊,該管道在創建管理線程之前創建,在成功啟動 了管理線程之後,管理管道的讀端和寫端分別賦給兩個全局變數__pthread_manager_reader和 __pthread_manager_request,之後,每個用戶線程都通過__pthread_manager_request向管理線程發請求, 但管理線程本身並沒有直接使用__pthread_manager_reader,管道的讀端(manager_pipe[0])是作為__clone ()的參數之一傳給管理線程的,管理線程的工作主要就是監聽管道讀端,並對從中取出的請求作出反應。
創建管理線程的流程如下所示:
(全局變數pthread_manager_request初值為-1)
圖3 創建管理線程的流程
初始化結束後,在__pthread_manager_thread中記錄了輕量級進程號以及核外分配和管理的線程id, 2*PTHREAD_THREADS_MAX+1這個數值不會與任何常規用戶線程id沖突。管理線程作為pthread_create()的調用者線程的 子線程運行,而pthread_create()所創建的那個用戶線程則是由管理線程來調用clone()創建,因此實際上是管理線程的子線程。(此處子 線程的概念應該當作子進程來理解。)
__pthread_manager()就是管理線程的主循環所在,在進行一系列初始化工作後,進入while(1)循環。在循環中,線程以2秒為 timeout查詢(__poll())管理管道的讀端。在處理請求前,檢查其父線程(也就是創建manager的主線程)是否已退出,如果已退出就退出 整個進程。如果有退出的子線程需要清理,則調用pthread_reap_children()清理。
然後才是讀取管道中的請求,根據請求類型執行相應操作(switch-case)。具體的請求處理,源碼中比較清楚,這里就不贅述了。
3.線程棧
在LinuxThreads中,管理線程的棧和用戶線程的棧是分離的,管理線程在進程堆中通過malloc()分配一個THREAD_MANAGER_STACK_SIZE位元組的區域作為自己的運行棧。
用戶線程的棧分配辦法隨著體系結構的不同而不同,主要根據兩個宏定義來區分,一個是NEED_SEPARATE_REGISTER_STACK,這個屬 性僅在IA64平台上使用;另一個是FLOATING_STACK宏,在i386等少數平台上使用,此時用戶線程棧由系統決定具體位置並提供保護。與此同 時,用戶還可以通過線程屬性結構來指定使用用戶自定義的棧。因篇幅所限,這里只能分析i386平台所使用的兩種棧組織方式:FLOATING_STACK 方式和用戶自定義方式。
在FLOATING_STACK方式下,LinuxThreads利用mmap()從內核空間中分配8MB空間(i386系統預設的最大棧空間大小,如 果有運行限制(rlimit),則按照運行限制設置),使用mprotect()設置其中第一頁為非訪問區。該8M空間的功能分配如下圖:
圖4 棧結構示意
低地址被保護的頁面用來監測棧溢出。
對於用戶指定的棧,在按照指針對界後,設置線程棧頂,並計算出棧底,不做保護,正確性由用戶自己保證。
不論哪種組織方式,線程描述結構總是位於棧頂緊鄰堆棧的位置。
4.線程id和進程id
每個LinuxThreads線程都同時具有線程id和進程id,其中進程id就是內核所維護的進程號,而線程id則由LinuxThreads分配和維護。
