linux系統線程實現原理淺析

背景

對進程和線程的理解,之前一直都是憑一些零碎不完整的信息在理解;

linux的進程和線程基本上一樣,線程是輕量級進程,彼此有關聯又獨立。

得虧內核支持的好,寫用戶態程序可以不依賴于實現的理解,只需要知道從哪個函數開始就是線程函數了,哪里的變量是全局的,哪里的變量是線程私有的。

這樣寫出來的程序也不至于有問題。

一直覺得沒有把這個東西搞清楚,終于受不了這種煎熬決定看下底層是怎么實現的。

線程/進程歷史

linux系統是先有進程的概念,后有線程的概念;

linux內核里面現有的線程實現,其實是redhat這個發行版廠商的實現,合入到linux主線了,redhat的實現就是現在的glibc里面的nptl(Native?POSIX Thread Library)加上內核fork共同協作實現的

除了NPTL,還有IBM的開源實現NGPT,后面沒有被納入內核,停止維護;

Linux內核也實現了Linux Threads,對比NPTL優勢不明顯吧

Linux線程實現概述

用戶態(glibc)+內核態組合共同實現

用戶態做的事情

線程attribute賦值(如果需要)

線程運行時用戶態運行的棧空間分配(包括棧空間的緩存和分配,大小、棧地址)

glibc的線程對象創建以及初始化

內核態做的事情

clone系統調用在調用do_fork時,主要flag有:CLONE_VM | CLONE_FS | CLONE_FILES

CLONE_VM表示和創建線程的進程共享地址空間

CLONE_FS表示和創建線程的進程共享文件系統(根目錄、工作目錄、文件創建掩碼等)

CLONE_FILES表示和創建線程的進程共享打開的文件

創建線程用的clone和創建真進程fork的區別是什么

fork在內核也是調用do_fork函數,fork系統調用在調用do_fork創建新的進程時,只攜帶了SIGCHLD這一個flag,其實就是不共享地址空間、打開的文件、使用的文件系統等,其它的和clone基本沒有區別。

說線程是輕量級進程就是這個原因,和創建它的進程共享了一部分主要資源。

后文把線程、輕量級進程、進程統一稱為進程,linux系統里面進程是內核支持的,線程是輕量級進程的別名(我認為這樣好理解,沒有官方說法支持)

用戶態和內核態如何配合達到效果

進程是對CPU的虛擬化,CPU是用來執行二進制程序的,二進制可以是用戶態也可以是內核態;也就是進程既可以執行用戶態代碼,也可以執行內核態代碼,進程是一個邏輯概念,內核態/用戶態代碼是表示運行指令時CPU處在不同的保護模式(ring0還是ring3)

進程是由內核態創建,進程主要作用是做為調度一員,獲取CPU時間片、地址空間、文件系統、打開文件、進程權限、用戶權限、cpu親和性、調度算法、進程組、運行時間、命名空間等信息(其它信息可以看task_struct的定義)

進程如何創建和運行起來

long do_fork(...)
{struct task_struct *p;p = copy_process(clone_flags, stack_start, stack_size,child_tidptr, NULL, trace, NUMA_NO_NODE);wake_up_new_task(p);}

依據clone_flags(用戶態或者系統調用時添加的flags)的不同使用copy_process創建一個新的進程p;

新創建的進程p執行了wake_up_new_task后就會被調度進程調度運行,進程被調度就會分配CPU運行。

如何執行用戶態線程函數

用戶態線程函數如何觸發執行

glibc里面pthread_create在X86_64的實現里面會調用__clone函數(clone.S,clone的實現之一)

1、用戶線程函數地址調用pthread_create后如何保存

用戶調用glibc函數創建線程時傳遞下來的fn地址是放在rdi這個寄存器(clone.S注釋有說明,應該也是遵循ABI函數調用堆棧參數保存約定的)。

注意這里的fn其實是glibc的start_thread函數,這個函數再調用戶的線程函數,指針保存在start_routine成員里面,具體代碼如下

if (pd->c11){/* The function pointer of the c11 thread start is cast to an incorrecttype on __pthread_create_2_1 call, however it is casted back to correctone so the call behavior is well-defined (it is assumed that pointersto void are able to represent all values of int.  */int (*start)(void*) = (int (*) (void*)) pd->start_routine;ret = (void*) (uintptr_t) start (pd->arg);}
elseret = pd->start_routine (pd->arg);

2、fn如何被調用

fn是用戶態地址,確實沒有必要傳遞到內核函數里面在內核態調用,這樣就牽扯到地址轉換了

那如何調用?在clone系統調用之前,把fn地址壓到子進程的棧里面,系統調用返回后,再彈出地址,通過call執行函數,相關代碼為:

ENTRY (__clone)......movq	%rdi,0(%rsi)............movl	$SYS_ify(clone),%eax....../* End FDE now, because in the child the unwind info will bewrong.  */cfi_endproc;syscalltestq	%rax,%raxjl	SYSCALL_ERROR_LABELjz	L(thread_start)retL(thread_start):popq	%rax		/* Function to call.  */popq	%rdi		/* Argument.  */call	*%rax

內核態如何找到用戶態的棧

glibc創建棧空間后,棧起始地址以及棧大小會通過系統調用的參數傳遞到內核

(如上面copy_process函數的第二個和第三個參數)

接下來內核調用copy_thread(clone_flags, stack_start, stack_size, p)(不同的架構對應不同的實現)

*childregs = *current_pt_regs();childregs->ax = 0;
if (sp)childregs->sp = sp;

這里對應的是X86_64的實現,可以看到把用戶態傳下來的棧指針設置到棧寄存器里面

這里有個點,這個sp和上面保存fn的棧是一個嗎?是用戶態分配的棧嗎?

我認為是的,這個是已經push過參數和fn之后的棧。

其它

為什么線程的棧要用戶分配在用戶態?

A:棧要么分在用戶態,要么分在內核態

如果分在用戶態,線程主循環函數運行在用戶態,都是在用戶態,就不需要CPU模式切換,運行速度更快,都是用戶態代碼也不存在對內核的安全問題

如果分在內核態,那用戶態函數執行,函數執行要不停操作棧,那至少就會有內核地址到用戶態地址的轉換,要不要牽扯模式切換就另說了。

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

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

相關文章

MySQL連接報錯處理:1130-host ... is not allowed to connect to this MySql server

在MySQL安裝完成后,很多開發者會遇到這樣一個問題: 錯誤代碼 1130:host xxx.xxx.xxx.xxx is not allowed to connect to this MySql server 這個錯誤通常出現在你嘗試通過遠程工具(如 Navicat、DBeaver 等)連接 MySQL …

Linux系統之----進程控制

1.進程創建 進程創建部分由于就是fork函數,還有寫時拷貝,在上一篇已經講述過了,這里不在進行贅述,有疑問的讀者可以前往上一篇博文《Linux系統--程序地址空間》中閱讀! 這里在多說一嘴寫時拷貝吧 我們可以對比一下寫…

Spring框架的設計目標,設計理念,和核心是什么 ?

Spring框架是一個為簡化企業級應用開發而設計的開源框架,它提供了全面的基礎設施支持,使得Java應用開發更加簡單、快速和可維護。下面我將詳細解釋Spring框架的設計目標、設計理念以及核心組件。 設計目標 簡化Java企業級應用開發:通過提供…

Red Hat6.4環境下搭建DNS服務器

DNS服務器(Domain Name System Server)是互聯網中用于將域名(如 www.example.com)解析為IP地址(如 192.0.2.1)的服務器。它是互聯網基礎設施的重要組成部分,幫助用戶通過易于記憶的域名訪問網站…

Nginx核心功能 02

目錄 Nginx代理技術核心概念 (一)正向代理(Forward Proxy) 1. 基本定義 2. 技術原理 3. 應用場景 (二)反向代理(Reverse Proxy) 1. 基本定義 2. 技術原理 3. 應用場景 一、…

關于Python:3. Python標準庫和常用模塊

1. os 和 sys(系統編程基礎) 這兩個模塊是進行系統層面操作(如文件管理、路徑處理、環境變量訪問等)必不可少的工具。 os 模塊 os 主要是用于與操作系統交互的,比如: 文件和目錄操作 獲取系統信息 運行…

Java基于SaaS模式多租戶ERP系統源碼

目錄 一、系統概述 二、開發環境 三、系統功能介紹 一、系統概述 ERP,全稱 Enterprise Resource Planning 即企業資源計劃。是一種集成化的管理軟件系統,它通過信息技術手段,將企業的各個業務流程和資源管理進行整合,以提高企業…

個人健康中樞的多元化AI網絡革新與精準健康路徑探析

引言 隨著數字化轉型的深入推進,個人健康中樞作為集成化健康管理系統,正在從傳統的單一功能向多元化的AI驅動方向快速發展。在這一背景下,新興網絡硬件技術,特別是DPU(數據處理單元)和全光網絡的出現,為個人健康中樞的革新提供了前所未有的機遇。本研究將深入探討這些技…

AI跑得快,MCP來加速——模型計算平臺在訓練與推理中的硬核作用

AI跑得快,MCP來加速——模型計算平臺在訓練與推理中的硬核作用 一、引言:AI是“鐵人三項”,但訓練+推理常常“掉鏈子” 如今的人工智能系統越來越強,像ChatGPT、Stable Diffusion、Segment Anything等模型不斷刷新技術天花板。但你是否也注意到: 明明模型設計得挺好,訓練…

《MATLAB實戰訓練營:從入門到工業級應用》工程實用篇-自動駕駛初體驗:車道線檢測算法實戰(MATLAB2016b版)

《MATLAB實戰訓練營:從入門到工業級應用》工程實用篇-🚗 自動駕駛初體驗:車道線檢測算法實戰(MATLAB2016b版) 大家好!今天我要帶大家一起探索自動駕駛中一個非常基礎但又至關重要的技術——車道線檢測。我…

模型部署——cuda編程入門

CUDA中的線程與線程束 kernel是在device上線程中并行執行的函數&#xff0c;核函數用__global__符號聲明&#xff0c;在調用時需要用<<<grid_size, block_size>>>來指定kernel要執行的線程數量。在CUDA中&#xff0c;每一個線程都要執行核函數&#xff0c;并…

WordPress不支持中文TAG標簽出現404的解決方法

我們在后臺編輯文章時輸入中文標簽會發現出現404的情況&#xff0c;其實中文TAG標簽鏈接無法打開的原因是WordPress不支持中文的編碼。那么解決的方法也很容易&#xff0c;只要改代碼讓WordPress能支持中文的編碼形式&#xff0c;也就是UTF-8和GBK編碼即可&#xff0c;無需用到…

金融信貸公司所需的技術和風控體系及其帶來的價值

金融信貸公司的技術架構通過集成傳統大型機系統與現代數據平臺&#xff0c;能夠有效支持金融信貸業務的運作&#xff0c;同時通過大數據、ETL、報表開發、數據倉庫等技術為公司帶來更高效的數據驅動決策、精準的風控分析和更靈活的業務支持。 一、公司技術架構 數據倉庫架構&…

《AI大模型應知應會100篇》第43篇:大模型幻覺問題的識別與緩解方法

第43篇&#xff1a;大模型幻覺問題的識別與緩解方法 摘要 當AI系統自信滿滿地編造"量子計算機使用香蕉皮作為能源"這類荒謬結論時&#xff0c;我們不得不正視大模型的幻覺問題。本文通過15個真實案例解析、6種檢測算法實現和3套工業級解決方案&#xff0c;帶您掌握…

計算方法實驗五 插值多項式的求法

【實驗性質】 綜合性驗 【實驗目的】 掌握Lagrange插值算法、Newton插值算法&#xff1b;理解Newton插值算法相對于Lagrange插值算法的優點。 【實驗內容】 先用C語言自帶的系統函數sin x求出 的值&#xff0c;然后分別用Lagrange、Newton方法求出的值&#xff0c;并與用…

文獻總結:TPAMI端到端自動駕駛綜述——End-to-End Autonomous Driving: Challenges and Frontiers

端到端自動駕駛綜述 1. 文章基本信息2. 背景介紹3. 端到端自動駕駛主要使用方法3. 1 模仿學習3.2 強化學習 4. 測試基準4.1 真實世界評估4.2 在線/閉環仿真測試4.3 離線/開環測試評價 5. 端到端自動駕駛面臨的挑戰5.1 多模態輸入5.2 對視覺表征的依賴5.3 基于模型的強化學習的世…

PostgreSQL:pgAdmin 4 使用教程

pgAdmin 4 是一個用于管理和維護 PostgreSQL 數據庫的強大工具。它提供了一個圖形化界面&#xff0c;使用戶能夠輕松地連接到數據庫、創建表、運行 SQL 語句以及執行其他數據庫管理任務。 安裝和使用 安裝 pgAdmin 4 安裝 pgAdmin 4 非常簡單。下載并運行安裝程序&#xff0…

Java學習手冊:關系型數據庫基礎

一、關系型數據庫概述 關系型數據庫是一種基于關系模型的數據庫&#xff0c;它將數據組織成一個或多個表&#xff08;或稱為關系&#xff09;&#xff0c;每個表由行和列組成。每一列都有一個唯一的名字&#xff0c;稱為屬性&#xff0c;表中的每一行是一個元組&#xff0c;代…

wpf CommandParameter 傳遞MouseWheelEventArgs參數

在 WPF 中通過 CommandParameter 傳遞 MouseWheelEventArgs 參數時&#xff0c;需結合 ?事件到命令的轉換機制? 和 ?參數轉換器? 來實現。以下是具體實現方案及注意事項&#xff1a; 一、核心實現方法 1. ?使用 EventToCommand 傳遞原始事件參數? 通過 Interaction.Tr…

八大排序之選擇排序

本篇文章將帶你詳細了解八大基本排序中的選擇排序 目錄 &#xff08;一&#xff09;選擇排序的時間復雜度和空間復雜度及穩定性分析 &#xff08;二&#xff09;代碼實現 (三)輸出結果 選擇排序的基本原理是&#xff1a;每次從待排序的數組中找出最大值和最小值。具體流程是…