Linux 線程的概念

序言:

在這篇博客中我們將講解線程的概念,如何理解線程,線程和進程的區別,線程的優缺點等,我相信你看完這篇博客后會以別樣的視角重新理解線程,下面的內容全部是基于Linux操作系統的。

一、線程的概念

1.1、重新理解地址空間

在外面之前的博客中我們說過:進程 = 內核數據結構 + 自己的代碼和數據。內核數據結構,代碼和數據都需要保存在內存中。它們都經過內核頁表或者用戶頁表進行映射到地址空間讓我們的進程看見這些資源,換一句話來說地址空間不就是進程的 “窗口” 嗎?,因為進程大部分的數據都需要直接或者間接(比如棧,加載的庫,進程的代碼和數據,內核的代碼和數據等等)通過地址空間看見。

下面我們回答一些問題讓我們的理解更加深刻:

缺頁中斷是怎么回事?

現在我們帶入一個場景:

當我們malloc的時候,操作系統會做什么?

操作系統會根據我們需要的大小在我們的地址空間開辟一塊空間(mm_struct的end和start指針上下移動就可以在地址空間開辟空間),但我們的操作系統并沒有在我們的物理內存上為我們開辟真正的空間,如果當我們使用這一塊空間的時候CPU上的MMU寄存器在進行虛擬地址和物理地址轉化的時候失敗觸發中斷CPU保護現場拿到中斷號,然后去中斷向量表去執行指定的中斷方法(在物理內存上開辟空間,創建頁表建立虛擬地址和物理地址的映射)執行完成再恢復現場去執行進程下面的代碼)。

看完上面對缺頁中斷的處理方法,我們有一種體會:只要我們的進程有了虛擬地址那么我們就一定還會有物理地址,只是當我們申請空間的時候開辟還是當我們真實使用的時候才會去開辟。

那么我們得出來一個結論:進程有多少虛擬地址就代表進程有多少資源,換一句話來說地址空間就是資源的代表。

教材給進程的定義是:進程是承擔分配系統資源的基本實體。

這句話應該如何去理解呢?

當我們創建一個進程的時候,操作系統會創建PCB,地址空間,用戶頁表等,這些都是需要占據CPU或者內存資源,所以進程是分配系統資源的基本實體。

1.2、什么是線程?

如果現在我們在一個主進程創建一個 “進程”(這里的進程只需要PCB不需要創建地址空間等內核數據),這個“新進程”可以看見和使用主進程的系統資源。如果可以把資源劃分給不同的PCB再讓不同的PCB執行對應的資源,這就是線程的概念。

如何去劃分資源?

地址空間就是資源的代表,劃分地址空間不就相當于劃分資源嗎?,劃分地址空間換一句話來說不就相當于劃分虛擬地址范圍,如果我們可以讓不同的執行流去執行不同的函數不就相當于去劃分了資源。

為什么執行不同的函數就相當于劃分資源?

當我們的函數編譯成匯編代碼以后每一句代碼都有自己的地址,這些地址不就是虛擬地址嗎?換一句話來說函數就是虛擬地址的集合,函數天然就幫我們劃分好了資源,當我們給不同的PCB不同的入口代碼地址那么這些PCB可以并發的執行起來了。

教材給線程的定義是:線程是進程內部的一個執行流。

站在內核和資源的角度給線程的定義:線程是CPU調度的基本單位。

如何去理解我們之前說的進程?

我們之前說進程是一個執行流的,它有PCB內核結構也有進程的代碼和數據加載到內存中,那這和我們上面說的線程不是一樣嗎?其實不一樣,我們給進程的定義是:進程 = 內核數據結構 +? 自己的代碼和數據。

下面我們來看一副圖來理解一下:

上面圖上畫紅框的才是進程,畫綠框的才是線程,我們可也有說進程中包含線程。我們之前說的那種進程是一種特殊的形式:單線程的進程。

站在操作系統和CPU的角度如何去理解線程?

在Linux中并沒有為了線程單獨設計內核數據結構而是用來以前進程的PCB,這樣做的好處是操作系統的調度算法不需要再重新設計,因為PCB的結構沒有改變,所以在系統看來都是一個一個的執行流,操作系統做進程調用的時候只要調度一個個的執行就好了。

Linux:一個個執行流的概念。

CPU:一種輕量級的進程,因為線程比任何的進程都要更小,換一句話來說 線程 <= 進程。

二、物理內存的管理

2.1、管理頁的結構體

內存中一些空間正在被創建一些需要被銷毀等,我們的內存這么大的空間我們如何去管理它呢?答案還是 “先描述,再組織” 。在我們內核數據結構中有struct page用來管理我們的內存空間。

下面我們來看一下struct page結構體:

struct page {unsigned long flags;		/* Atomic flags, some possibly* updated asynchronously */atomic_t _count;		/* Usage count, see below. */union {atomic_t _mapcount;	/* Count of ptes mapped in mms,* to show when page is mapped* & limit reverse map searches.*/struct {		/* SLUB */u16 inuse;u16 objects;};};union {struct {unsigned long private;		/* Mapping-private opaque data:* usually used for buffer_heads* if PagePrivate set; used for* swp_entry_t if PageSwapCache;* indicates order in the buddy* system if PG_buddy is set.*/struct address_space *mapping;	/* If low bit clear, points to* inode address_space, or NULL.* If page mapped as anonymous* memory, low bit is set, and* it points to anon_vma object:* see PAGE_MAPPING_ANON below.*/};
#if USE_SPLIT_PTLOCKSspinlock_t ptl;
#endifstruct kmem_cache *slab;	/* SLUB: Pointer to slab */struct page *first_page;	/* Compound tail pages */};union {pgoff_t index;		/* Our offset within mapping. */void *freelist;		/* SLUB: freelist req. slab lock */};struct list_head lru;		/* Pageout list, eg. active_list* protected by zone->lru_lock !*//** On machines where all RAM is mapped into kernel address space,* we can simply calculate the virtual address. On machines with* highmem some memory is mapped into kernel virtual memory* dynamically, so we need a place to store that address.* Note that this field could be 16 bits on x86 ... ;)** Architectures with slow multiplication can define* WANT_PAGE_VIRTUAL in asm/page.h*/
#if defined(WANT_PAGE_VIRTUAL)void *virtual;			/* Kernel virtual address (NULL ifnot kmapped, ie. highmem) */
#endif /* WANT_PAGE_VIRTUAL */
#ifdef CONFIG_WANT_PAGE_DEBUG_FLAGSunsigned long debug_flags;	/* Use atomic bitops on this */
#endif#ifdef CONFIG_KMEMCHECK/** kmemcheck wants to track the status of each byte in a page; this* is a pointer to such a status block. NULL if not tracked.*/void *shadow;
#endif
};

struct page結構體的成員變量

flags:用來存放頁的狀態,一共有32種狀態。

_mapcount:這個頁被多少個頁表引用。

virtual:這個也在地址空間里的虛擬地址。

strcut page的大小大概是40多字節全部的頁的struct page放在一起也不過40MB對內存資源的銷毀并不大。

內存天然是4KB大小塊劃分的嗎?

答案是不是的,內存是被操作系統分為4KB大小的塊的,內存本身是一塊連續的空間。

為什么要以4KB為大小?

這個是科學家經過測試出來的4KB的效率更高,當然也有很多其他的因素,比如歷史,硬件等。

下面我想補充幾個概念:

頁框和頁幀:現在在教材中頁幀和頁框的概念是相同的了,它們都表示在磁盤中或者在內存中4KB的存儲空間。

頁:表示4KB頁框中存儲的數據內容。

2.2、如何去申請空間?

在操作系統中我們可以認為管理struct page結構體通過數組的方式管理

那么我們如何去申請一塊空間呢?

我們可以現在struct page數組中尋找到一個struct page我們知道了它的下標,再去更改struct page中的flag標志位將未占用改為占用,然后通過下標index * 4KB就可以找到內存中具體的頁框地址。

申請內存的流程是:

如何去銷毀對應的空間呢?

通過物理地址 / 4KB找到對應struct page的下標,再去更改struct page里的flag標記位,就可以了。

三、如何去理解頁表?

按32位的機器來說,我們的內存有4GB如果按照我們說的左邊是虛擬地址右邊是物理地址的形式,那光光頁表如果是全部映射的話就需要32GB(4GB * 8字節)的大小,在我們的操作系統里肯定會有很多的進程,我們的內存全部用來存頁表都不夠,這種方式顯然是不可能是我們操作系統實現頁表的方法。

那么我們的操作系統是如何實現對頁表的保存的:多級頁表的形式。

3.1、多級頁表

32位機器中地址一共32位個比特位,操作系統把32個比特位分為三份,第一份為0~10位,第二份為11~20位,第三份為21~32位,它們三個分別承擔了不同的任務。

在頁目錄表項存儲的是:頁表的地址。

在頁表表項存儲的是:具體物理內存頁框的地址。

前10為比特位作為索引去查找頁目錄找到對應的頁表地址,再用中間10為比特位來作為索引查找頁表找到對應的頁框的地址,最后再用最后12位比特位來作為具體的頁內偏移去訪問具體的字節內容。

我們前面說過 具體的物理地址 = 物理內存頁框地址 + 頁內偏移,通過上面這種多級頁表的方式就可以訪問具體的字節。

下面我們來回答幾個問題:

為什么頁內偏移設置成地址的低12位?

這個問題的答案在前20位上,一個頁框內的地址是不是前20位都是一樣的,我們在訪問一句代碼的時候根據局部性原理我們很有可能訪問這句代碼周圍的代碼和數據,如果訪問的數據是在附近的那么它們的前20位很可能是相同的它們只要低12位是不一樣的,這也就說明它們在同一個頁框中我們可以用盡量少次數的訪問把它們全部找到效率高。

我們的用戶用的全部都是虛擬地址通過什么去進行轉化?

在我們的CPU中集成了MMU和CR3寄存器,CR3中存放的是頁目錄的地址,MMU可以根據CR3提供的頁目錄地址去查找頁目錄,頁表進而將虛擬地址轉化成物理地址。

MMU要先進?兩次?表查詢確定物理地址,在確認了權限等問題后,MMU再將這個物理地址發送到總線,內存收到之后開始讀取對應地址的數據并返回。那么當?表變為N級時,就變成了N次檢索+1次讀寫,這也就說明了多級頁表的一個缺點:效率低。
?

多級頁表和單張頁表的優缺點:

多級頁表:

優點:省空間。

缺點:如果頁表分級比較多查找需要多次降低效率。

單級頁表:

優點:效率高,只需要查找一次。

缺點:需要占據的內存大小比較大。

3.2、頁表的優點

1、維護進程的獨立性

如果沒有頁表,進程直接去訪問物理空間,如果有惡意軟件直接去改變其他進程的數據,就可能導致其他軟件的錯誤導致進程被殺死,進而進程的安全性無法保證。

2、高效利用物理內存
離散分配:進程的虛擬地址空間可以映射到物理內存中不連續的頁框(物理頁),避免了傳統連續內存分配導致的 “內存碎片” 問題,提高了物理內存的利用率。
按需加載:結合分頁機制,進程無需將全部數據加載到物理內存即可運行(僅加載當前需要的頁),實現了 “部分加載”,讓有限的物理內存可以支持更多進程并發運行。

3、?支持內存共享與保護
共享內存:多個進程的頁表可映射到同一物理頁框(如共享庫、進程間通信的共享內存區域),實現內存內容的共享,減少重復存儲,節省物理內存。
權限控制:頁表項(PTE)中包含權限位(如讀、寫、執行權限),操作系統可通過設置這些位限制對內存頁的操作(如只讀頁禁止修改、數據頁禁止執行),防止非法訪問(如緩沖區溢出攻擊)。

四、缺頁中斷怎么回事?

當我們給CPU一個虛擬地址的時候,它會先去到TLB(我們之前在《Linux Ext文件系統》中介紹過)中去尋找,沒有找到,它再去把虛擬地址給MMU,MMU再去通過CR3提供的頁目錄地址去想你找對應的頁表,也沒有找到,這個時候觸發軟中斷。

Page Falut Handler:在磁盤中找到對應的數據,在struct page中申請內存空間,將磁盤中的數據載入到內存中申請頁表建立頁表和物理內存的映射關系,然后返回。

=========================================================================

本篇關于Linux的文件理解與操作的介紹就暫告段落啦,希望能對大家的學習產生幫助,歡迎各位佬前來支持糾正!!!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/97907.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/97907.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/97907.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

vscode 中通義靈碼顯示登錄過期

本文主要分享&#xff1a;vscode 中通義靈碼顯示登錄過期的解決辦法。vscode 中的小插件通義靈碼&#xff0c;用的好好的&#xff0c;突然提示&#xff1a;登錄過期&#xff0c;嘗試訪問網頁版阿里云&#xff0c;登錄后&#xff0c;關閉 vscode 重新打開&#xff0c;通義靈碼還…

ESP32C3-MINI-1開發板踩坑記錄

某東買了一個ESP32C3-MINI-1開發板&#xff0c;名字跟ESP官網的很像&#xff0c;想著應該差不多的&#xff0c;價格便宜17塊&#xff0c;而官網的就貴了60還不包郵&#xff0c;買來才發現是巨坑。 看結論&#xff0c;直接到最后&#xff0c;前面都是我的踩坑過程。第一塊板子發…

基于粒子群算法的山地環境無人機最短路徑規劃研究(含危險區域約束的三維優化方法)

無人機在復雜地形與危險環境中的自主路徑規劃是保障任務順利執行的關鍵問題。本文針對山地環境下單無人機三維路徑規劃難題&#xff0c;提出了一種基于粒子群算法&#xff08;PSO&#xff09;的優化方法。首先&#xff0c;建立了包含真實地形高程、危險區域和飛行約束條件的三維…

Linux-> UDP 編程2

目錄 本文說明 一&#xff1a;字典程序的幾個問題 1&#xff1a;字典的本質 2&#xff1a;翻譯功能的本質 3&#xff1a;讓服務端和翻譯功能相關聯 二&#xff1a;字典類(Dict.hpp) 1&#xff1a;加載詞典(Load) 2&#xff1a;翻譯單詞(Translate) 三&#xff1a;服務…

輝視養老方案:重塑老年生活的溫馨與安心

在當今社會&#xff0c;隨著老齡化進程的加速&#xff0c;如何為老年人提供更加便捷、舒適且安全的養老環境&#xff0c;成為了全社會共同關注的焦點。輝視養老方案應運而生&#xff0c;它以科技為翼&#xff0c;以關愛為心&#xff0c;通過遠程探望、客控系統、信息服務、IPTV…

SQuAD:機器閱讀理解領域的里程碑數據集

本文由「大千AI助手」原創發布&#xff0c;專注用真話講AI&#xff0c;回歸技術本質。拒絕神話或妖魔化。搜索「大千AI助手」關注我&#xff0c;一起撕掉過度包裝&#xff0c;學習真實的AI技術&#xff01; 1 什么是SQuAD&#xff1f; SQuAD&#xff08;Stanford Question Ans…

【vim,Svelte】怎樣使用 vim 編輯 Svelte 那些奇奇怪怪名字的文件?

當你要使用 vim&#xff08;或者neovim&#xff09;來編輯 Svelte 下面的文件時&#xff0c;比如這些文件&#xff1a; page.svelte layout.svelte$ vim page.svelte $ vim "page.svelte" $ vim page.svelte $ vim \page.svelte使用上面的命令&#xff0c;你會遇到這…

深入解析 HTTP 狀態碼

在日常的網絡瀏覽和 Web 開發過程中&#xff0c;我們總會不可避免地遇到各種 HTTP 狀態碼。比如常見的 “404 Not Found”&#xff0c;它意味著我們所請求的頁面不存在&#xff1b;還有 “500 Internal Server Error”&#xff0c;表示服務器端出現了錯誤。這些由三位數字組成的…

【C++】C++類和對象—(中)

前言&#xff1a;在上一篇類和對象(上)的文章中我們已經帶領大家認識了類的概念&#xff0c;定義以及對類和對象的一些基本操作&#xff0c;接下來我們要逐步進入到類和對象(中)的學習。我們將逐步的介紹類和對象的核心——類和對象的六個默認成員函數。(注意&#xff1a;這六個…

使用python-fastApi框架開發一個學校宿舍管理系統-前后端分離項目

今天給大家分享一個我最近做的一個學校宿舍管理系統&#xff0c;python版&#xff0c;這個系統實現的功能有&#xff1a;首頁 | 學校管理 | 宿舍樓管理 | 宿舍管理 | 學生管理 | 學生調宿 | 學生退宿 | 報修等級 | 宿舍衛生評分 | 違紀記錄 | 管理員管理 。一共有11個菜單。 使…

阻塞 vs 非阻塞:程序等待的兩種哲學

當程序需要等待外部操作時&#xff0c;是應該"干等"還是"邊等邊干"&#xff1f;為什么有些程序會卡住不動&#xff0c;而另一些卻能流暢運行&#xff1f;這一切都取決于阻塞與非阻塞的編程選擇&#xff01;本文將為你揭示這兩種模式的本質區別&#xff01;…

MySQL 核心操作全解析(用戶 + SHOW+DML+DCL)

MySQL 核心操作全解析&#xff08;用戶 SHOWDMLDCL&#xff09; 基于你提供的實操筆記&#xff0c;我們將 MySQL 核心操作拆解為用戶管理、SHOW 查詢命令、DML 數據操作、TRUNCATE 與 DELETE 對比、DCL 權限控制五大模塊&#xff0c;梳理語法邏輯、補充避坑提示&#xff0c;幫…

多語言編碼Agent解決方案(6)-部署和使用指南

部署和使用指南 本指南提供完整的部署和使用說明&#xff0c;幫助您設置后端服務并在VSCode、Eclipse和IntelliJ中使用相應的插件。這個解決方案基于vLLM提供AI編碼輔助&#xff0c;支持英語、中文和日文。 前提條件 操作系統&#xff1a;Linux、macOS或Windows&#xff08;推薦…

濾波器的三重境界:從信號處理到自動駕駛測試的基石

在自動駕駛的宏大敘事中&#xff0c;我們常常聚焦于人工智能、深度學習、高精地圖等"明星技術"。然而&#xff0c;在這些耀眼的光環背后&#xff0c;有一個低調卻至關重要的"幕后英雄"——濾波器。它不僅是信號處理的工具&#xff0c;更是連接物理世界與數…

Part4.第8章:神經網絡

第8章 激活函數 如果沒有激活函數&#xff0c;不論幾層的神經網絡都是一個線性回歸。激活函數的作用是引入非線性。

nextjs+shadcn+tailwindcss實現博客中的overview

最近在用nextjsshadcntailwindcss練手&#xff0c;實現一個博客。做到了overView這里&#xff0c;可實現如下效果1.首先要安裝tailwindcss&#xff0c;這個在創建項目的時候就安裝了。2.然后安裝shadcn,官網教程&#xff1a;3.代碼如下&#xff1a;import {Card,CardContent } …

Kotlin 高階語法解析

Kotlin 高級語法深度解析1. 協程&#xff08;Coroutines&#xff09;1.1 基礎概念1.掛起和恢復2.協程構建器 (Coroutine Builders)3.協程作用域4.調度器1.2 核心用法1.3 實戰示例2. 密封類&#xff08;Sealed Classes&#xff09;2.1 定義與特性2.2 模式匹配2.3 應用場景3. 內聯…

9 基于機器學習進行遙感影像參數反演-以隨機森林為例

目錄 1 讀取數據 2 數據預處理 3模型訓練 4模型預測 5精度分析 由于回歸任務的標簽數據獲取比較困難,我們這次用水體指數NDWI來模擬作為回歸任務的標簽,通過隨機森林來擬合回歸NDWI,其計算公式如下: NDWI = (band3 - band5) / (band3 + band5) 實際情況下需要回歸的數…

C++多線程編程:跨線程操作全解析

C中的"線程"通常指單個執行流&#xff08;如std::thread對象&#xff09;&#xff0c;而"多線程"指程序中同時存在多個這樣的執行流&#xff0c;并涉及它們的創建、管理和同步。實現跨線程操作的核心在于安全地處理共享數據和線程間通信。 以下是實現跨線程…

【腦電分析系列】第13篇:腦電源定位:從頭皮到大腦深處,EEG源定位的原理、算法與可視化

前言腦電信號&#xff08;Electroencephalography, EEG&#xff09;是一種非侵入性的神經成像技術&#xff0c;能夠實時捕捉大腦的電活動。然而&#xff0c;頭皮上記錄到的信號是腦源活動經過頭皮、顱骨等介質“模糊”后的投影。想要從這些頭皮EEG信號追溯到大腦深處的電活動&a…