【Linux】線程——線程的概念、線程的特點、線程的優點和缺點、線程和進程、線程函數的使用

文章目錄

  • Linux線程
    • 1. 線程的概念
      • 1.1 什么是線程
    • 2. 線程的特點
      • 2.1 線程的優點
      • 2.2 線程的缺點
      • 2.4 線程和進程
    • 3. 線程函數的使用
      • pthread_create() 創建線程
      • pthread_self() 獲取線程ID
      • pthread_exit() 線程終止
      • pthread_cancel() 線程取消
      • pthread_join() 線程等待
      • pthread_detach()線程分離

Linux線程

1. 線程的概念

??我們之前認識到,進程是程序的一個執行實例,是正在執行的程序等,這是從進程本身來看的,從內核上看,進程擔當分配系統資源(CPU時間,內存)的實體,是聯系硬件和軟件的橋梁。

??通常進程包含:進程獨立的程序地址空間和頁表,通常是我們說的虛擬內存;
進程擁有系統分配的各種資源;標識進程唯一性和保存執行信息的進程控制塊(PCB);執行的程序代碼和相關的數據;打開的文件和設備;進程上下文。

??當一個進程要執行大量任務的時候,一個單進程通常只有一個執行流,只能執行一個時間片,這樣無法提高計算機的運行效率,所以我們要在進程中使用線程。

??通過線程,我們可以提高計算機的運行效率。線程是進程中的執行單元,多個線程可以共享進程的資源,如內存空間、文件描述符等。這樣使得多個線程可以在同一個進程中并發執行,將復雜的任務分解為多個子任務,每一個子任務有線程執行,充分利用CPU的時間片,減少等待時間,提高系統運行效率。

??簡單總結:

??進程因為包含很多資源,開銷較大,線程在進程內部開銷較小。

??多線程有多個時間片且并發執行,資源共享,運行效率較高。

??

1.1 什么是線程

??(1)在一個程序里的一個執行路線就叫做線程(thread)。更準確的定義是:線程是“一個進程內部的控制序列”。

??(2)一切進程至少都有一個執行線程。

??(3)線程在進程內部運行,本質是在進程地址空間內運行。

??(4)在Linux系統中,在CPU眼中,看到的PCB都要比傳統的進程更加輕量化,所以Linux 下的線程看作輕量級進程。

??(5)透過進程虛擬地址空間,可以看到進程的大部分資源,將進程資源合理分配給每個執行流,就形成了線程執行流。

??總結:線程是進程中的一個實體,作為系統調度和分派的基本單位。

在這里插入圖片描述

??

2. 線程的特點

2.1 線程的優點

??(1)創建一個新線程的代價要比創建一個新進程小得多

??(2)與進程之間的切換相比,線程之間的切換需要操作系統做的工作要少很多

??(3)線程占用的資源要比進程少很多

??(4)能充分利用多處理器的可并行數量

??(5)在等待慢速I/O操作結束的同時,程序可執行其他的計算任務

??(6)計算密集型應用,為了能在多處理器系統上運行,將計算分解到多個線程中實現

??(7)I/O密集型應用,為了提高性能,將I/O操作重疊。線程可以同時等待不同的I/O操作。

??

2.2 線程的缺點

??(1)性能損失:一個很少被外部事件阻塞的計算密集型線程往往無法與共它線程共享同一個處理器。如果計算密集型線程的數量比可用的處理器多,那么可能會有較大的性能損失,這里的性能損失指的是增加了額外的同步和調度開銷,而可用的資源不變。

??(2)健壯性降低:編寫多線程需要更全面更深入的考慮,在一個多線程程序里,因時間分配上的細微偏差或者因共享了不該共享的變量而造成不良影響的可能性是很大的,換句話說線程之間是缺乏保護的。

??(3)缺乏訪問控制:進程是訪問控制的基本粒度,在一個線程中調用某些OS函數會對整個進程造成影響。

??(4)編程難度提高:編寫與調試一個多線程程序比單線程程序困難得多

??

2.4 線程和進程

進程和線程的區別:

??(1)調度單位:進程是資源分配的基本單位,線程是調度的基本單位。

??(2)資源擁有:進程擁有獨立的地址空間和系統資源,線程共享進程資源,但也擁有自己的一部分資源:線程ID、一組寄存器、棧、errno、信號屏蔽字、調度優先級。

??(3)系統開銷:創建或撤銷進程時,系統需要分配或回收資源,開銷較大;線程的創建和撤銷開銷相對較小。

??(4)通信方式:進程間通信較為復雜,需要使用特定的進程間通信機制,如管道、消息隊列等;線程間通信相對簡單,可以通過共享內存等方式直接進行。

??(5)健壯性:進程間相互獨立,一個進程的崩潰一般不會影響其他進程;線程一個線程的崩潰可能影響整個進程。

??此外因為進程的多個線程共享同一地址空間,因此Text Segment、Data Segment都是共享的,如果定義一個函數,在各線程中都可以調用,如果定義一個全局變量,在各線程中都可以訪問到,除此之外,各線程還共享以下進程資源和環境:文件描述符表,每種信號的處理方式(SIG_ IGN、SIG_ DFL或者自定義的信號處理函數)當前工作目錄,用戶id和組id。

在這里插入圖片描述

??

3. 線程函數的使用

??POSIX線程庫:與線程有關的函數構成了一個完整的系列,絕大多數函數的名字都是以“pthread_”打頭的,要使用這些函數庫,要通過引入頭文<pthread.h>,鏈接這些線程函數庫時要使用編譯器命令的“-lpthread”選項。

pthread_create() 創建線程

功能:創建一個新的線程

原型:

int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine)(void*), void *arg);

參數:

??thread:返回線程ID
??attr:設置線程的屬性,attr為NULL表示使用默認屬性
??start_routine:是個函數地址,線程啟動后要執行的函數
??arg:傳給線程啟動函數的參數

返回值:

??成功返回0;失敗返回錯誤碼

錯誤檢查:

??傳統的一些函數是,成功返回0,失敗返回-1,并且對全局變量errno賦值以指示錯誤。

??pthreads函數出錯時不會設置全局變量errno(而大部分其他POSIX函數會這樣做)。而是將錯誤代碼通過返回值返回pthreads同樣也提供了線程內的errno變量,以支持其它使用errno的代碼。

??對于pthreads函數的錯誤,建議通過返回值判定,因為讀取返回值要比讀取線程內的errno變量的開銷更小。

??

進程地址空間布局

??pthread_ create函數會產生一個線程ID,存放在第一個參數指向的地址中。該線程ID和前面說的線程ID不是一回事。

??前面講的線程ID屬于進程調度的范疇。因為線程是輕量級進程,是操作系統調度器的最小單位,所以需要一個數值來唯一表示該線程。

??pthread_ create函數第一個參數指向一個虛擬內存單元,該內存單元的地址即為新創建線程的線程ID,屬于NPTL線程庫的范疇。線程庫的后續操作,就是根據該線程ID來操作線程的。

??線程庫NPTL提供了pthread_ self函數,可以獲得線程自身的ID。

??pthread_t 到底是什么類型呢?取決于實現。對于Linux目前實現的NPTL實現而言,pthread_t類型的線程ID,本質就是一個進程地址空間上的一個地址。

在這里插入圖片描述

??

pthread_self() 獲取線程ID

pthread_t pthread_self(void);

功能:通過 pthread_self() 函數可以獲取到當前線程的 ID。

??

pthread_exit() 線程終止

功能:線程終止

原型:

void pthread_exit(void *value_ptr);

參數:
??value_ptr:value_ptr不要指向一個局部變量。

返回值:
??無返回值,跟進程一樣,線程結束的時候無法返回到它的調用者(自身)。

??如果需要只終止某個線程而不終止整個進程,可以有三種方法:

??(1)從線程函數return。這種方法對主線程不適用,從main函數return相當于調用exit。

??(2)線程可以調用pthread_ exit終止自己。

??(3)一個線程可以調用pthread_ cancel終止同一進程中的另一個線程。

??需要注意,pthread_exit或者return返回的指針所指向的內存單元必須是全局的或者是用malloc分配的,不能在線程函數的棧上分配,因為當其它線程得到這個返回指針時線程函數已經退出了。

??

pthread_cancel() 線程取消

功能:取消一個執行中的線程。

原型:

int pthread_cancel(pthread_t thread);

參數:
??thread:線程ID

返回值:
??成功返回0;失敗返回錯誤碼。

??

pthread_join() 線程等待

功能:等待線程結束

原型:

int pthread_join(pthread_t thread, void **value_ptr);

參數:
??thread:線程ID
??value_ptr:它指向一個指針,后者指向線程的返回值

返回值:
??成功返回0;失敗返回錯誤碼

??

為什么需要線程等待?

??1. 已經退出的線程,其空間沒有被釋放,仍然在進程的地址空間內。

??2. 創建新的線程不會復用剛才退出線程的地址空間。

??

??調用該函數的線程將掛起等待,直到id為thread的線程終止。thread線程以不同的方法終止,通過pthread_join得到的終止狀態是不同的,總結如下:

??(1)如果thread線程通過return返回,value_ ptr所指向的單元里存放的是thread線程函數的返回值。

??(2)如果thread線程被別的線程調用pthread_ cancel異常終掉,value_ ptr所指向的單元里存放的是常數PTHREAD_ CANCELED。

??(3)如果thread線程是自己調用pthread_exit終止的,value_ptr所指向的單元存放的是傳給pthread_exit的參數。

??(4)如果對thread線程的終止狀態不感興趣,可以傳NULL給value_ ptr參數。

??

pthread_detach()線程分離

??功能:將一個線程設置為分離狀態。當一個線程被分離后,它所占用的資源在其終止時會由系統自動回收,而無需其他線程通過 pthread_join 來等待并回收資源

int pthread_detach(pthread_t thread);

??默認情況下,新創建的線程是joinable的,線程退出后,需要對其進行pthread_join操作,否則無法釋放資源,從而造成系統泄漏。

??如果不關心線程的返回值,join是一種負擔,這個時候,我們可以告訴系統,當線程退出時,自動釋放線程資源。

??可以是線程組內其他線程對目標線程進行分離,也可以是線程自己分離:

pthread_detach(pthread_self());

??

使用多線程模擬一個簡單的多線程加減乘除計算過程

#include <iostream>
#include <pthread.h>
#include <vector>
#include <cstring>
#include <string>
#include <cstdlib>
#include <unistd.h>
#include <ctime>char op[4]={'+','-','*','/'};//計算請求
class Request
{
public:Request(int id,int n1,int n2,int op):_id(id),_n1(n1),_n2(n2),_op(op){}
public:int _id;int _n1;int _n2;char _op;
};//計算結果
class Response
{
public:Response(std::string request, int result):_request(request),_result(result),_errno(0){}
public:std::string _request;int _result;int _errno;
};//執行計算的函數
void* handler(void *args)
{Request *rq=static_cast<Request*>(args);std::string req="thread "+std::to_string(rq->_id)+" : "+std::to_string(rq->_n1)\+rq->_op+std::to_string(rq->_n2);int res,flag=0;switch (rq->_op) {case '+':res = rq->_n1 + rq->_n2;break;case '-':res = rq->_n1 - rq->_n2;break;case '*':res = rq->_n1 * rq->_n2;break;case '/':if (rq->_n2 != 0) {res = rq->_n1 / rq->_n2;} else {flag=1;std::cerr << "Error: Division by zero!" << std::endl; }break;}Response *rsp=new Response(req,res);if(flag==1) rsp->_errno=1;std::cout<<"thread is working"<<std::endl;//std::cout<<rq->_id<<" thread result : "<<rq->_n1<<"+"<<rq->_n2<<"="<<rsp->_result<<std::endl;//usleep(1000);return rsp;
}//我們使用多線程模擬一個簡單的多線程加減乘除計算過程
void test2()
{//設置隨機數種子std::srand(static_cast<unsigned int>(std::time(nullptr)));//模擬10次加減乘除計算過程std::vector<pthread_t> threads;std::vector<Response*> responses; // 用于存儲每個線程的返回值for(int i=1;i<=10;i++){pthread_t tid;int n1=rand()%10;int n2=rand()%10;Request *rq=new Request(i,n1,n2,op[n1%4]);pthread_create(&tid,nullptr,handler,rq);threads.push_back(tid); // 將線程句柄存儲起來}for(auto& thread:threads){void *ret;pthread_join(thread,&ret);Response *rsp = static_cast<Response *>(ret);std::cout<<rsp->_result<<std::endl;std::cout << "rsp->result: " << rsp->_result <<std::endl;    responses.push_back(rsp); // 將 Response 對象存儲起來}// 輸出每個線程的計算結果for (auto rsp : responses){if(rsp->_errno==1)  {std::cout <<rsp->_request << " result: " << "division by zero error" << std::endl;}else {std::cout <<rsp->_request << " result: " << rsp->_result << std::endl;}delete rsp; // 釋放每個 Response 對象的內存}
}

在這里插入圖片描述

??

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

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

相關文章

【第14章】MyBatis-Plus批量操作

文章目錄 前言一、功能概覽二、類結構說明1.MybatisBatch<?>2.MybatisBatch.Method<?>3. BatchMethod<?>4.使用步驟5.返回值說明 三、使用示例1. execute方法2. 示例一&#xff1a;實體類型數據3. 示例二&#xff1a;非實體類型數據4. 示例三&#xff1a;…

茗鶴 | 如何借助APS高級計劃排程系統提高汽車整車制造的效率

在我們做了詳盡的市場調研及頭部汽車制造企業排程需求溝通后&#xff0c;我們發現盡管企業有很多的業務系統做支撐&#xff0c;在計劃排程領域&#xff0c;所有的汽車制造總裝廠仍舊使用人工“Excel”做排產規劃&#xff0c;其中少部分也會借助MRP、第三方輔助排產工具。鑒于我…

ChatGPT:Java中的對象引用實現方式

ChatGPT&#xff1a;Java中的對象引用實現方式 如果使用句柄的話&#xff0c;那么 Java 堆中將會劃分出一塊內存來作為句柄池&#xff0c;reference 中存儲的就是對象的句柄地址&#xff0c;而句柄中包含了對象實例數據與對象類型數據各自的具體地址信息。 你提到的句柄機制是…

JVM原理(十一):JVM虛擬機六種必需對類進行初始化的情況

Java虛擬機把描述類的數據從Class文件加載到內存&#xff0c;并對數據進行校驗、轉換解析和初始化&#xff0c;最終形成可以被虛擬機直接使用的Java類型&#xff0c;這個過程被稱作虛擬機的類加載機制。Java天生可以動態擴展的語言特性就是依賴運行期間動態加載和動態鏈接這個特…

104.二叉樹的最大深度

給定一個二叉樹 root &#xff0c;返回其最大深度。 二叉樹的 最大深度 是指從根節點到最遠葉子節點的最長路徑上的節點數。 示例 1&#xff1a; 輸入&#xff1a;root [3,9,20,null,null,15,7] 輸出&#xff1a;3 示例 2&#xff1a; 輸入&#xff1a;root [1,null,2] 輸出…

相機參數與圖像處理技術解析

01. 相機內參和外參的含義&#xff1f;如果將圖像放大兩倍&#xff0c;內外參如何變化&#xff1f; 相機有兩個最基礎的數據&#xff1a;內參(Instrinsics)和外參(Extrinsics)&#xff0c;內參主要描述的是相機的CCD/CMOS感光片尺寸/分辨率以及光學鏡頭的系數&#xff0c;外參主…

每日兩題 / 20. 有效的括號 155. 最小棧(LeetCode熱題100)

20. 有效的括號 - 力扣&#xff08;LeetCode&#xff09; 遇到左括號入棧 遇到右括號判斷棧頂是否為匹配的左括號 最后判斷棧是否為空 func isValid(s string) bool {var stk []runefor _, value : range s {if value ( || value { || value [ {stk append(stk, value)}…

阿里巴巴圖標庫iconfont的使用方式

文章目錄 什么是 iconfong創建一個自己的項目如何使用Unicode 使用方法Font class 使用方式Symbol 使用方式還有一種使用方式 在線鏈接&#xff08;不推薦&#xff0c;但可用于測試&#xff09; 什么是 iconfong Iconfont 是一種圖標字體服務。它將各種圖標設計轉換為字體格式…

數據庫的約束與索引

數據庫的約束與索引 文章目錄 數據庫的約束與索引一、約束1、定義2、主鍵索引3、唯一約束4、非空約束5、外鍵約束 二、索引1、定義2、主鍵索引3、唯一索引4、普通索引5、全文索引 三、深入索引面試題&#xff08;一&#xff09;面試題&#xff08;二&#xff09;面試題&#xf…

【設計模式】行為型-狀態模式

在變幻的時光中&#xff0c;狀態如詩篇般細膩流轉。 文章目錄 一、可調節的燈光二、狀態模式三、狀態模式的核心組件四、運用狀態模式五、狀態模式的應用場景六、小結推薦閱讀 一、可調節的燈光 場景假設&#xff1a;我們有一個電燈&#xff0c;它可以被打開和關閉。用戶可以…

snap和apt的區別簡單了解

Linux中沒有tree命令的時候提示安裝的時候出現了兩個命令&#xff0c;簡單看了看兩者有何區別&#xff08;一般用apt就可以了&#xff09;&#xff1a; sudo snap install tree 和 sudo apt install tree 這兩個命令都是用來安裝 tree 命令行工具的&#xff0c;但它們使用的是不…

在線教育平臺,easyexcel使用案例

控制器 因為如何想要在讀數據的時候操作數據庫&#xff0c;就必須使用構造方法傳dao 或者service&#xff0c;因為這個不歸spring管理&#xff0c;不能自動注入&#xff0c;所以參數里需要傳遞service 或者 dao AutowiredIEduSubjectService subjectService;添加課程分類的方法…

Anaconda學習常見問題匯總

問題1&#xff1a;Fatal error in launcher: Unable to create process using ‘“d:\anaconda\isntall\envs\learn1\python.exe 在進行anaconda學習時&#xff0c;在控制臺輸入&#xff1a;pip list想要查看環境里的內容時發生錯誤&#xff1a; Fatal error in launcher: Un…

個人博客|PHP源碼|支持多國語言切換

一. 前言 今天小編給大家帶來了一款可學習&#xff0c;可商用的&#xff0c;支持多國語言的個人博客網站源碼&#xff0c;支持二開&#xff0c;無加密。此博客相當簡潔&#xff0c;也適合海外。詳細界面和功能見下面視頻演示。 如果您正好有此需求源碼&#xff0c;請聯系小編…

軟件資產管理系統:提升企業軟件資產透明度與合規性的終極解決方案!

在當今數字化轉型浪潮中&#xff0c;企業軟件資產管理的重要性日益凸顯。然而&#xff0c;傳統的手工管理方式往往效率低下&#xff0c;難以應對快速變化的軟件環境。SmartLic軟件資產管理系統應運而生&#xff0c;它以先進的技術手段&#xff0c;為企業提供全面的軟件資產管理…

開源自動化熱鍵映射工具autohotkey十大用法及精選腳本

AutoHotkey&#xff08;AHK&#xff09;是一款功能強大的熱鍵腳本語言工具&#xff0c;它允許用戶通過編寫腳本來自動化鍵盤、鼠標等設備的操作&#xff0c;從而極大地提高工作效率。以下是AutoHotkey的十大經典用法&#xff0c;這些用法不僅解放了用戶的雙手&#xff0c;還展示…

程序化交易廣告及其應用

什么是程序化交易廣告&#xff1f; 程序化交易廣告是以實時競價技術即RTB&#xff08;real-time bidding&#xff09;為核心的廣告交易方式。說到這里&#xff0c;你可能會有疑問&#xff1a;像百度搜索關鍵詞廣告還有百度網盟的廣告&#xff0c;不也是CPC實時競價的嗎&#x…

MDX的魔法:探索SQL Server中的多維表達式

&#x1f4ca; MDX的魔法&#xff1a;探索SQL Server中的多維表達式 在商業智能和數據分析領域&#xff0c;SQL Server提供了一種強大的工具來處理多維數據集&#xff0c;這就是多維表達式&#xff08;Multidimensional Expressions&#xff0c;簡稱MDX&#xff09;。MDX是一種…

論文學習_UVSCAN: Detecting Third-Party Component Usage Violations in IoT Firmware

論文名稱發表時間發表期刊期刊等級研究單位 Understanding the Security Risks Introduced by Third-Party Components in IoT Firmware 2024年IEEE TDSCCCF A佐治亞理工學院 1. 引言 研究背景&#xff1a;物聯網&#xff08;IoT&#xff09;已經無處不在&#xff0c;為我們…

HQChart報價列表高級應用教程7-走勢列數據對接

HQChart報價列表高級應用教程7-走勢列數據對接 走勢列小程序效果圖PC效果圖HQChart代碼地址走勢列類型配置走勢列數據格式示例走勢列 單獨使用一列顯示每個股票的走勢圖 小程序效果圖 PC效果圖 HQChart代碼地址 地址:github.com/jones2000/HQChart 走勢列類型 REPORT_COL…