Linux線程入門

目錄

Linux線程概念

什么是線程

重新理解進程

線程的優點

線程的缺點

線程的異常

線程用途


Linux線程概念

什么是線程

  • 在一個程序里的一個執行路線就叫做線程(thread)。更準確的定義是:線程是“一個進程內部的控制序列”。
  • 一切進程至少都有一個執行線程。
  • 線程在進程內部運行,本質是在進程地址空間內運行。
  • 在Linux系統中,在CPU眼中,看到的PCB都要比傳統的進程更輕量化。
  • 透過進程虛擬地址空間,可以看到進程的大部分資源,將進程資源合理分配給每個執行流,就形成了線程執行流。

根據前言知識,我們創建一個進程的時候,實際上伴隨著其進程控制塊(task_struct)、進程地址空間(mm_struct)以及頁表的創建,而虛擬地址與物理地址就是通過頁表映射的。

對于每一個進程的創建都會經過此過程,所以每個進程都是相互獨立的,互不干擾的。

對于前面線程的定義來說,一個程序中的一個執行路線就叫線程, 一切進程至少又一個執行線程。所以我們可以簡單的知道進程與線程的一個簡單的關系:線程是進程的一個執行分支。

除此之外,線程是在進程內部運行的,本質在進程的地址空間上運行,并且進程的資源合理分配給每一個執行流。所以我們可以簡單畫出線程創建的結果:

此時我們創建了四個線程。

  • 其每一個線程都是進程的一個執行流,也就是我們說的執行分支。
  • 其每一個線程都是在進程內部運行的,都是在進程地址空間內運行的。
  • 并且,進程資源合理分配給每個執行流,幾乎都是被所有線程共享的。

所以簡單的來說,一個進程可以包含多個線程,這些線程共享進程的資源。

單純從技術角度,這個是一定能實現的,因為它比創建一個原始進程所做的工作更輕量化了。

?那么剛剛了解了線程,肯定會對以前對進程的了解有一定的困惑,那該如何重新理解之前的進程?

重新理解進程

如圖用紅色方框框起來的內容,我們將這個整體叫做進程。

因此,對于進程的定義,進程 = 內核數據結構 + 程序的代碼和數據,此定義就不準確了。不能簡簡單單通過task_struct來衡量了。所以的定義應該是 進程 = 多個內核數據結構 + 程序的代碼和數據 + 所占的物理內存

現在我們應該站在內核角度來理解進程:承擔分配系統資源的基本實體,叫做進程。

換言之,當我們創建進程時是創建一個task_struct、創建地址空間、維護頁表,然后在物理內存當中開辟空間、構建映射,打開進程默認打開的相關文件、注冊信號對應的處理方案等等。

而我們之前接觸到的進程都只有一個task_struct,也就是該進程內部只有一個執行流,即單執行流進程,反之,內部有多個執行流的進程叫做多執行流進程。

在Linux中,站在CPU的角度,是什么樣呢?

根據前言對進程的學習,CPU是無法直接以進程為單位進行調度的,而是通過一個隊列,然后task_struct?通過內嵌的?sched_entity?間接參與隊列。

站在CPU的角度,能否識別當前調度的task_struct是進程還是線程?

答案是不能的,而且也不需要。因為CPU只關心一個一個的獨立執行流。無論進程內部只有一個執行流還是有多個執行流,對于CPU而言,只需要將執行流安排好,以他們為基本單位進行調度即可。

單執行流被調度

多執行流被調度

?所以在Linux系統中,對于CPU來說,雖然看到的是task_struct,但是比傳統的PCB要更加輕量化。

  • 傳統PCB:在經典操作系統中,PCB是描述進程的核心數據結構,包含進程的所有信息(PID、狀態、內存映射、文件描述符、上下文等)。

  • Linux的task_struct:雖然名字叫“任務結構體”,但它實際是線程的抽象(因為Linux不區分進程和線程,均用task_struct表示)。一個進程可能包含多個task_struct(多線程時),共享同一份資源(如內存空間)。

所以在Linux系統下,對CPU而言,線程<=執行流<=進程。

所以在Liunx系統下,線程是基本調度單位,線程也就是task_struct!!!但僅限Linux下。

Linux下并不存在真正的線程!而是用進程模擬的!

操作系統中存在大量的進程,一個進程內又存在一個或多個線程,因此線程的數量一定比進程的數量多,當線程的數量足夠多的時候,很明顯線程的執行粒度要比進程更細。

如果一款操作系統要支持真的線程,那么就需要對這些線程進行管理。比如說創建線程、終止線程、調度線程、切換線程、給線程分配資源、釋放資源以及回收資源等等,所有的這一套相比較進程都需要另起爐灶,搭建一套與進程平行的線程管理模塊。

因此,如果要支持真的線程一定會提高設計操作系統的復雜程度。在Linux看來,描述線程的控制塊和描述進程的控制塊是類似的,因此Linux并沒有重新為線程設計數據結構,而是直接復用了進程控制塊,所以我們說Linux中的所有執行流都叫做輕量級進程。

但也有支持真的線程的操作系統,比如Windows操作系統,因此Windows操作系統系統的實現邏輯一定比Linux操作系統的實現邏輯要復雜得多。

既然在Linux沒有真正意義的線程,那么也就絕對沒有真正意義上的線程相關的系統調用!

這很好理解,既然在Linux中都沒有真正意義上的線程了,那么自然也沒有真正意義上的線程相關的系統調用了。但是Linux可以提供創建輕量級進程的接口,也就是創建進程,共享空間,其中最典型的代表就是vfork函數。

vfork函數的功能就是創建子進程,但是父子共享空間,v函數fork的函數原型如下:

pid_t vfork(void);

vfork函數的返回值與fork函數的返回值相同:

  • 給父進程返回子進程的PID。
  • 給子進程返回0。

只不過vfork函數創建出來的子進程與其父進程共享地址空間,例如在下面的代碼中,父進程使用vfork函數創建子進程,子進程將全局變量g_val由100改為了200,父進程休眠3秒后再讀取到全局變量g_val的值。

#include <iostream>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>using namespace std;int g_val = 100;int main()
{pid_t id = vfork();if (id == 0){//childg_val = 200;printf("child:PID:%d, PPID:%d, g_val:%d\n", getpid(), getppid(), g_val);exit(0);}// fathersleep(2);printf("father:PID:%d, PPID:%d, g_val:%d\n", getpid(), getppid(), g_val);return 0;
}

父進程讀取到g_val的值是子進程修改后的值,也就證明了vfork創建的子進程與其父進程是共享地址空間的。

其實這樣暗示了fork創建的子進程并不屬于線程!!! fork創建的是完整的子進程,該子進程是父進程的完整副本

線程的優點

  • 創建一個新線程的代價要比創建一個新進程小得多
  • 與進程之間的切換相比,線程之間的切換需要操作系統做的工作要少很多
  • 線程占用的資源要比進程少很多
  • 能充分利用多處理器的可并行數量
  • 在等待慢速I/O操作結束的同時,程序可執行其他的計算任務
  • 計算密集型應用,為了能在多處理器系統上運行,將計算分解到多個線程中實現
  • I/O密集型應用,為了提高性能,將I/O操作重疊。線程可以同時等待不同的I/O操作。

線程的缺點

  • 性能損失:一個很少被外部事件阻塞的計算密集型線程往往無法與共它線程共享同一個處理器。如果計算密集型線程的數量比可用的處理器多,那么可能會有較大的性能損失,這里的性能損失指的是增加了額外的同步和調度開銷,而可用的資源不變。
  • 健壯性降低:編寫多線程需要更全面更深入的考慮,在一個多線程程序里,因時間分配上的細微偏差或者因共享了不該共享的變量而造成不良影響的可能性是很大的,換句話說線程之間是缺乏保護的。
  • 缺乏訪問控制:進程是訪問控制的基本粒度,在一個線程中調用某些OS函數會對整個進程造成影響。
  • 程難度提高:編寫與調試一個多線程程序比單線程程序困難得多

線程的異常

  • 單個線程如果出現除零,野指針問題導致線程崩潰,進程也會隨著崩潰
  • 線程是進程的執行分支,線程出異常,就類似進程出異常,進而觸發信號機制,終止進程,進程終止,該進程內的所有線程也就隨即退出

線程用途

  • 合理的使用多線程,能提高CPU密集型程序的執行效率
  • 合理的使用多線程,能提高IO密集型程序的用戶體驗(如生活中我們一邊寫代碼一邊下載開發工具,就是多線程運行的一種表現)

最用再用一張圖在總結一下

?這篇文章僅僅是對線程的一個簡單的入門,后面還會對線程進行更為詳細的講解與其應用場景!

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

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

相關文章

通信應用高速模數轉換器ADC

在5G通信、醫療成像、航空航天及工業自動化等關鍵領域&#xff0c;高速ADC模數轉換器作為信號鏈的“心臟”&#xff0c;其性能直接決定了系統的精度與效率。然而&#xff0c;如何精確測試高速ADC的動態參數、優化設計驗證流程、應對復雜應用場景的挑戰&#xff0c;始終是工程師…

PostgreSQL 中 JSONB 數據類型的深度解析以及如何使用

一、JSONB 核心特性解析 1. 存儲結構與優勢 ??二進制存儲??&#xff1a;將 JSON 數據解析為二進制格式&#xff08;分解鍵值對&#xff0c;去除空格和重復鍵&#xff09;??高效查詢??&#xff1a;支持 GIN/GiST 索引&#xff0c;查詢速度比 JSON 類型快 10 倍??數據…

C++_核心編程_ 左移運算符重載 “<<” 左移運算符

作用&#xff1a;可以輸出自定義數據類型 */ //目標 調用p1,輸出Person 中的屬性 m_A ,m_B &#xff1a; /* #### 4.5.2 左移運算符重載 “<<” 左移運算符 作用&#xff1a;可以輸出自定義數據類型 *///目標 調用p1,輸出Person 中的屬性 m_A ,m_B &#xff1a; class…

thinkphp 5.1 部分知識記錄<一>

1、配置基礎 慣例配置->應用配置->模塊配置->動態配置 慣例配置:核心框架內置的配置文件,無需更改。應用配置:每個應用的全局配置文件(框架安裝后會生成初始的應用配置文件),有部分配置參數僅能在應用配置文件中設置。模塊配置:每個模塊的配置文件(相同的配置…

數據結構 -- 樹相關面試題

二、樹相關的填空題 1.對于一個具有 n 個結點的二叉樹&#xff0c;當它為一棵 ________ 二叉樹時&#xff0c;具有最小高度&#xff0c;即為 ________&#xff1b;當它為一棵單支樹時具有最大高度&#xff0c;即為 ________。 2.對于一個具有 n 個結點的二叉樹&#xff0c;當它…

2025河北CCPC 題解(部分)

簽到題&#xff1a;AC代碼如下 &#xff1a; // Problem: H - What is all you need? // Contest: Virtual Judge - sdccpc20250526 // URL: https://vjudge.net/contest/718568#problem/H // Memory Limit: 1024 MB // Time Limit: 1000 ms // // Powered by CP Editor (ht…

計算機視覺---YOLOv4

YOLOv4&#xff08;You Only Look Once v4&#xff09;于2020年由Alexey Bochkovskiy等人提出&#xff0c;是YOLO系列的重要里程碑。它在YOLOv3的基礎上整合了當時最先進的計算機視覺技術&#xff0c;實現了檢測速度與精度的顯著提升。以下從主干網絡、頸部網絡、頭部檢測、訓練…

OpenCV 第7課 圖像處理之平滑(一)

1. 圖像噪聲 在采集、處理和傳輸過程中,數字圖像可能會受到不同噪聲的干擾,從而導致圖像質量降低、圖像變得模糊、圖像特征被淹沒,而圖像平滑處理就是通過除去噪聲來達到圖像增強的目的。常見的圖像噪聲有椒鹽噪聲、高斯噪聲等。 1.1 椒鹽噪聲 椒鹽噪聲(Salt-and-pepper N…

Spring AI 系列3: Promt提示詞

一、Promt提示詞 Promt提示是引導 AI 模型生成特定輸出的輸入&#xff0c; 提示的設計和措辭會顯著影響模型的響應。 在 Spring AI 中與 AI 模型交互的最低層級&#xff0c;處理提示有點類似于在 Spring MVC 中管理”視圖”。 這涉及創建帶有動態內容占位符的大段文本。 這些占…

隨叫隨到的電力補給:移動充電服務如何重塑用戶體驗?

在快節奏的現代生活中&#xff0c;電力已成為維系日常運轉的隱形血脈。智能手機、電動汽車、便攜設備的普及&#xff0c;讓“電量焦慮”逐漸演變為一種時代癥候。而移動充電服務的興起&#xff0c;正悄然改變這一局面。它像一位隱形的能源管家&#xff0c;隨時響應需求&#xf…

LeetCode 75. 顏色分類 - 雙指針法高效解決(Java實現)

文章目錄 問題描述算法思路&#xff1a;三指針分區法核心思想指針定義 Java實現算法執行流程關鍵問題解析&#xff1a;為什么交換0后不需要重新檢查&#xff1f;交換0時的兩種情況分析詳細解釋&#xff1a; 復雜度分析示例演示&#xff08;輸入&#xff1a;[2,0,2,1,1,0]&#…

【MySQL】C語言連接

要使用C語言連接mysql&#xff0c;需要使用mysql官網提供的庫&#xff0c;大家可以去官網下載 我們使用C接口庫來進行連接 要正確使用&#xff0c;我們需要做一些準備工作: 保證mysql服務有效在官網上下載合適自己平臺的mysql connect庫&#xff0c;以備后用 下載開發庫 s…

NFS 掛載配置與優化最佳實踐指南

文章目錄 NFS 掛載配置與優化最佳實踐指南1. 服務器端配置1.1 安裝 NFS 服務1.2 配置共享目錄常用配置選項說明 1.3 啟動與檢查服務 2. 客戶端掛載2.1 安裝 NFS 客戶端2.2 掛載 NFS 共享2.3 自動掛載 3. 客戶端掛載選項4. 性能優化與故障排查4.1 性能優化建議4.2 常見問題排查 …

3D PDF如何制作?SOLIDWORKS MBD模板定制技巧

SOLIDWORKS制作3D PDF模版 SOLIDWORKS MBD能夠幫助工程師以清晰直觀的方式描述產品尺寸信息。在3D PDF文件中&#xff0c;用戶可以自由旋轉和移動視圖&#xff0c;方便查看模型的各個尺寸細節。 本文將帶您一步步學習如何使用SOLIDWORKS MBD制作專業的3D PDF模板&#xff0c;…

Unity-QFramework框架學習-MVC、Command、Event、Utility、System、BindableProperty

QFramework QFramework簡介 QFramework是一套漸進式、快速開發框架&#xff0c;適用于任何類型的游戲及應用項目&#xff0c;它包含一套開發架構和大量的工具集 QFramework的特性 簡潔性&#xff1a;QFramework 強調代碼的簡潔性和易用性&#xff0c;讓開發者能夠快速上手&a…

R3GAN訓練自己的數據集

簡介 簡介&#xff1a;這篇論文挑戰了"GANs難以訓練"的廣泛觀點&#xff0c;通過提出一個更穩定的損失函數和現代化的網絡架構&#xff0c;構建了一個簡潔而高效的GAN基線模型R3GAN。作者證明了通過合適的理論基礎和架構設計&#xff0c;GANs可以穩定訓練并達到優異…

【PhysUnits】15.1 引入P1后的加一特質(add1.rs)

一、源碼 代碼實現了類型系統中的"加一"操作&#xff08;Add1 trait&#xff09;&#xff0c;用于在編譯期進行數字的增量計算。 //! 加一操作特質實現 / Increment operation trait implementation //! //! 說明&#xff1a; //! 1. Z0、P1,、N1 1&#xff0…

記錄算法筆記(2025.5.29)最小棧

設計一個支持 push &#xff0c;pop &#xff0c;top 操作&#xff0c;并能在常數時間內檢索到最小元素的棧。 實現 MinStack 類: MinStack() 初始化堆棧對象。void push(int val) 將元素val推入堆棧。void pop() 刪除堆棧頂部的元素。int top() 獲取堆棧頂部的元素。int get…

Android高級開發第一篇 - JNI(初級入門篇)

文章目錄 Android高級開發JNI開發第一篇&#xff08;初級入門篇&#xff09;&#x1f9e0; 一、什么是 JNI&#xff1f;? 為什么要用 JNI&#xff1f; ?? 二、開發環境準備開發工具 &#x1f680; 三、創建一個支持 JNI 的 Android 項目第一步&#xff1a;創建新項目項目結構…

PyTorch Image Models (timm) 技術指南

timm PyTorch Image Models (timm) 技術指南功能概述 一、引言二、timm 庫概述三、安裝 timm 庫四、模型加載與推理示例4.1 通用推理流程4.2 具體模型示例4.2.1 ResNeXt50-32x4d4.2.2 EfficientNet-V2 Small 模型4.2.3 DeiT-3 large 模型4.2.4 RepViT-M2 模型4.2.5 ResNet-RS-1…