【Linux】—— 線程控制的基本介紹

目錄

(一)POSIX線程庫

(二)創建線程

2.1?線程ID及進程地址空間布局

(三)線程終止

(四)分離線程


(一)POSIX線程庫

POSIX線程庫(POSIX Threads Library),通常簡稱為Pthreads,是一個為POSIX操作系統(包括UNIX和類UNIX系統如Linux)提供線程支持的庫。Pthreads定義了一組API,允許程序員創建、管理、同步和銷毀線程。?

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

(二)創建線程

【函數介紹】?

功能:創建一個新的線程原型
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void * (*start_routine)(void*), void *arg);參數thread:返回線程IDattr:設置線程的屬性,attr為NULL表示使用默認屬性start_routine:是個函數地址,線程啟動后要執行的函數arg:傳給線程啟動函數的參數返回值:成功返回0;失敗返回錯誤碼

錯誤檢查

  1. 對于Pthreads函數,如果調用失敗,通常會返回一個非零的錯誤代碼,你可以使用這個錯誤代碼來查詢具體是什么錯誤發生了。為了將錯誤代碼映射到人類可讀的錯誤消息,你可以使用strerrorpthread_strerror函數(如果可用)。

  2. 另外,Pthreads庫確實為每個線程提供了一個私有的errno變量,這允許線程安全地訪問errno。然而,對于Pthreads函數本身來說,直接檢查返回值通常是更好的做法,因為這樣可以避免任何可能的線程間干擾,并且通常更加高效。

?【代碼示例】?

#include <iostream>
#include <unistd.h>
#include <pthread.h>using namespace std;int g_val = 0; void *threadRun1(void *args)
{while (true){sleep(1);cout << "t1 thread..." << getpid() << " &g_val: " << &g_val << " , g_val: " << g_val << endl;}
}void *threadRun2(void *args)
{while (true){sleep(1);cout << "t2 thread..." << getpid()  << " &g_val: " << &g_val << " , g_val: " << g_val++ << endl;}
}int main()
{pthread_t t1, t2;pthread_create(&t1, nullptr, threadRun1, nullptr);pthread_create(&t1, nullptr, threadRun2, nullptr);while (true){sleep(1);cout << "main thread..." << getpid()  << " &g_val: " << &g_val << " , g_val: " << g_val << endl;}
}

2.1?線程ID及進程地址空間布局

  1. pthread_ create函數會產生一個線程ID,存放在第一個參數指向的地址中。該線程ID和前面說的線程ID不是一回事。
  2. 前面講的線程ID屬于進程調度的范疇。因為線程是輕量級進程,是操作系統調度器的最小單位,所以需要一個數值來唯一表示該線程。
  3. pthread_ create函數第一個參數指向一個虛擬內存單元,該內存單元的地址即為新創建線程的線程ID,屬于NPTL線程庫的范疇。線程庫的后續操作,就是根據該線程ID來操作線程的。
  4. 線程庫NPTL提供了pthread_ self函數,可以獲得線程自身的ID

【函數介紹】?

pthread_t pthread_self(void);

錯誤檢查

  • 如果成功,pthread_self?返回調用線程的線程 ID。如果發生錯誤,這個函數沒有定義錯誤碼返回機制,因為它總是應該成功。

??【代碼示例】?

#include <iostream>  
#include <pthread.h>  
#include <unistd.h>using namespace std;void* threadRun(void* arg) {  pthread_t id = pthread_self(); // 獲取當前線程的 ID  cout << "the thread ID is :  " << id << endl;  sleep(1);  return nullptr;  
}  int main() {  pthread_t tid;  int ret;  // 創建線程  ret = pthread_create(&tid, nullptr, threadRun, nullptr);  if (ret != 0) {  cerr << "Error: pthread_create() failed with error " << ret << endl;  return 1;  }  // 等待線程完成  pthread_join(tid, nullptr);  cout << "Main thread exiting." << endl;  return 0;  
}

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


(三)線程終止

如果需要只終止某個線程而不終止整個進程 , 可以有三種方法 :
  • 1. 從線程函數return。這種方法對主線程不適用,main函數return相當于調用exit
#define NUM 10void *threadrun(void *args)
{char *name = (char*)args;while (true){cout << "new thread run, the new thread name is : " << name   << endl;sleep(3);break;}delete name;return  nullptr;
}int main()
{pthread_t tids[NUM];for(int i= 0; i< NUM; ++i){char *tname = new char[64];snprintf(tname,64,"thread-%d",i+1);pthread_create(tids+i,nullptr,threadrun,tname);}void *ret = nullptr;for(int i= 0; i< NUM; ++i){int n = pthread_join(tids[i],nullptr);if(n != 0) cerr << "pthread_join error" << endl;cout << "thread quit: " <<(uint64_t)ret << endl;}cout << "all thread quit..."<<endl; return 0;
}
  • 2. 線程可以調用pthread_ exit終止自己。

【函數介紹】?

功能:線程終止
原型void pthread_exit(void *value_ptr);
參數value_ptr:value_ptr不要指向一個局部變量。返回值:無返回值,跟進程一樣,線程結束的時候無法返回到它的調用者(自身)
  • 需要注意,pthread_exit或者return返回的指針所指向的內存單元必須是全局的或者是用malloc分配的,不能在線程函數的棧上分配,因為當其它線程得到這個返回指針時線程函數已經退出了。

?【代碼示例】?

#define NUM 10void *threadrun(void *args)
{char *name = (char*)args;while (true){cout << "new thread run, the new thread name is : " << name   << endl;sleep(3);break;}delete name;pthread_exit((void*)1); 
}int main()
{pthread_t tids[NUM];for(int i= 0; i< NUM; ++i){char *tname = new char[64];snprintf(tname,64,"thread-%d",i+1);pthread_create(tids+i,nullptr,threadrun,tname);}void *ret = nullptr;for(int i= 0; i< NUM; ++i){int n = pthread_join(tids[i],nullptr);if(n != 0) cerr << "pthread_join error" << endl;cout << "thread quit: " <<(uint64_t)ret << endl;}cout << "all thread quit..."<<endl; return 0;
}
  • 3. 一個線程可以調用pthread_ cancel終止同一進程中的另一個線程。

【函數介紹】?

功能:取消一個執行中的線程
原型int pthread_cancel(pthread_t thread);
參數thread:線程ID返回值:成功返回0;失敗返回錯誤碼

??【代碼示例】?

void *threadRun(void* args)
{const char*name = static_cast<const char *>(args);int cnt = 5;while(cnt){cout << name << " is running: " << cnt-- << " obtain self id: " << pthread_self() << endl;sleep(1);}pthread_exit((void*)11); // PTHREAD_CANCELED; #define PTHREAD_CANCELED ((void *) -1)
}int main()
{pthread_t tid;pthread_create(&tid, nullptr, threadRun, (void*)"thread 1");sleep(3);pthread_cancel(tid);void *ret = nullptr;pthread_join(tid, &ret);cout << " new thread exit : " << (int64_t)ret << "quit thread: " << tid << endl;return 0;
}

【輸出結果】(三秒后取消操作)


其次就是在上述代碼中,使用了線程等待函數,那為什么需要線程等待? ?

  • 已經退出的線程,其空間沒有被釋放,仍然在進程的地址空間內。
  • 創建新的線程不會復用剛才退出線程的地址空間。

?【函數介紹】

功能:等待線程結束原型int pthread_join(pthread_t thread, void **value_ptr);參數
thread:線程ID
value_ptr:它指向一個指針,后者指向線程的返回值返回值:成功返回0;失敗返回錯誤碼
調用該函數的線程將掛起等待 , 直到 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線程的終止狀態不感興趣,可以傳NULLvalue_ ptr參數。


(四)分離線程

  • 默認情況下,新創建的線程是joinable的,線程退出后,需要對其進行pthread_join操作,否則無法釋放資源,從而造成系統泄漏。
  • 如果不關心線程的返回值,join是一種負擔,這個時候,我們可以告訴系統,當線程退出時,自動釋放線程資源。

?【函數介紹】

int pthread_detach(pthread_t thread);

【代碼示例】?

void* threadRun(void* args) {   sleep(2);  cout << "線程任務已完成\n";  return nullptr;  
}  int main() {  pthread_t tid;  int ret;  // 創建線程  ret = pthread_create(&tid, nullptr, threadRun, nullptr);  if (ret) {  cerr << "Error: pthread_create() failed\n";  return 1;  }  // 分離線程  pthread_detach(tid);  // 主線程繼續執行  cout << "主線程繼續執行...\n";  // 主線程休眠一段時間以便觀察分離線程的輸出  sleep(3);  // 主線程結束,分離線程的資源會在其完成后由系統自動回收  return 0;  
}

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

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

相關文章

Node.js后端構建指南:MongoDB與Express的集成

安裝express 安裝 Express 并將其保存到依賴列表中&#xff1a; $ cnpm install express --save 以上命令會將 Express 框架安裝在當前目錄的 node_modules 目錄中&#xff0c; node_modules 目錄下會自動創建 express 目錄。以下幾個重要的模塊是需要與 express 框架一起安…

nss刷題(4)

1、[SWPUCTF 2021 新生賽]easyrce <?php error_reporting(0); highlight_file(__FILE__); if(isset($_GET[url])) { eval($_GET[url]); } ?> if(isset($_GET[url])) isset函數用來檢測url變量是否存在&#xff1b;$_GET函數獲取變量數據 eval($_GET[url]); eval函數用…

【GIS矢量切片】tippecanoe在Windows和CentOS中的安裝

組件安裝記錄 背景介紹Windows下安裝1、下載工具2、存放安裝包3、進入DOS終端4、在終端執行命令5、下載程序6、放置源碼7、修改配置信息8、編譯9、測試10、參數說明瓦片輸出瓦片描述和權屬信息輸入文件和圖層名輸入文件的并行處理輸入文件的投影縮放級別瓦片分辨率CentOS 7安裝…

嘗試用 GPT-4o 寫 2024高考語文作文

文章目錄 新課標I卷科技進步與問題的演變 新課標II卷抵達未知之境&#xff1a;探索與成長的旅程 全國甲卷坦誠交流&#xff1a;構建真正相遇的橋梁 北京卷歷久彌新 天津卷定義與自定義&#xff1a;在世界的繽紛中前行 上海卷認可度的思考與反思 新課標I卷 閱讀下面的材料&#…

Mongodb---java篇

一、導入依賴 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-mongodb</artifactId></dependency> 二、編寫配置文件連接Mongodb 我的認證數據庫是admin&#xff0c;你們可能不一樣 sp…

第三篇——大數據思維的科學基礎

目錄 一、背景介紹二、思路&方案三、過程1.思維導圖2.文章中經典的句子理解3.學習之后對于投資市場的理解4.通過這篇文章結合我知道的東西我能想到什么&#xff1f; 四、總結五、升華 一、背景介紹 大數據時代&#xff0c;大數據思維的重要性不言而喻&#xff1b;而信息在…

Elasticsearch搜索優化-自定義路由規劃(routing)

在es的實踐學習中&#xff0c;我覺得它的文檔是最好的老師&#xff0c;所以先把這部分鏈接貼出來&#xff0c;本文只是引導&#xff0c;文檔全是細節&#xff0c;還是推薦大家事后認真看看文檔 Metadata fields-routing 在es搜索中&#xff0c;請求是先分發到所有分片&#x…

6月26~28日,2024北京國際消防展即將開幕!

隨著社會的快速發展&#xff0c;消防安全日益受到廣大民眾的高度關注。為了進一步推動消防科技的創新與發展&#xff0c;提升全民消防安全意識&#xff0c;2024年北京消防展將于6月26日在北京國家會議中心盛大開展。目前:觀眾預登記已全面啟動&#xff0c;廣大市民和業界人士可…

馬爾科夫性質-舉例簡單說明,馬爾科夫模型和隱馬爾科夫模型在自然語言處理方面應用是什么

目錄 馬爾科夫模型應用 馬爾科夫性質,舉例簡單說明 馬爾科夫模型 馬爾科夫鏈 馬爾科夫決策過程(Markov Decision Process, MDP) 例子 隱馬爾科夫模型(Hidden Markov Model, HMM) 馬爾科夫模型和隱馬爾科夫模型在自然語言處理方面應用是什么 馬爾科夫模型在自然語言…

SQLite3(1):介紹安裝與測試

目錄 1、SQLite3介紹 2、SQLite3的優勢和特性 3、SQLite3安裝與測試 3.1 SQLite3安裝 3.2 SQLite3測試 4、SQLite3簡單使用 4.1 連接數據庫文件 4.2 創建信息表 4.3 插入三個學生信息 4.4 確認信息 5、總結 1、SQLite3介紹 SQLite3是一種輕量級的關系型數據庫管理系…

論文閱讀 A Distributional Framework for Data Valuation

本論文解決的問題 量化數據價值&#xff08;機器學習模型訓練中各個數據點的貢獻&#xff09; 避免數據價值受到其所處數據集的影響&#xff0c;使數據點的估值更加穩定、一致 變量假設 假設 D 表示一個在全集 Z 上的數據分布。對于監督學習問題&#xff0c;我們通常認為 Z…

jvm學習筆記(一) ----- JAVA 內存

JAVA 內存 一、程序計數器二、虛擬機棧三、本地方法棧四、堆五、非JAVA內存(堆外內存)1.元空間(Metaspace)2.直接內存 鏈接: jvm學習筆記(二) ----- 垃圾回收 鏈接: jvm學習筆記(三) ----- 垃圾回收器 一、程序計數器 虛擬機需要通過『程序計數器』記錄指令執行到哪了。線程要…

代碼隨想錄算法訓練營day43

題目&#xff1a;1049. 最后一塊石頭的重量 II 、494. 目標和、474.一和零 參考鏈接&#xff1a;代碼隨想錄 1049. 最后一塊石頭的重量 II 思路&#xff1a;本題石頭是相互粉碎&#xff0c;粉碎后剩下的重量就是兩塊石頭之差&#xff0c;我們可以想到&#xff0c;把石頭分成…

使用智譜 GLM-4-9B 和 SiliconCloud 云服務快速構建一個編碼類智能體應用

本篇文章我將介紹使用智譜 AI 最新開源的 GLM-4-9B 模型和 GenAI 云服務 SiliconCloud 快速構建一個 RAG 應用&#xff0c;首先我會詳細介紹下 GLM-4-9B 模型的能力情況和開源限制&#xff0c;以及 SiliconCloud 的使用介紹&#xff0c;最后構建一個編碼類智能體應用作為測試。…

數據結構和算法之數組和鏈表

一、數組 數組是一種線性數據結構&#xff0c;它是由一組連續的內存單元組成的&#xff0c;用于存儲相同類型的數據。在JavaScript中&#xff0c;數組可以包含任意類型的數據&#xff0c;不只限于基本數據類型。 1.存儲方式 在內存中&#xff0c;數組的元素是連續存儲的&…

【Vue】組件的存放目錄問題

注意&#xff1a; .vue文件 本質無區別 組件分類 .vue文件分為2類&#xff0c;都是 .vue文件&#xff08;本質無區別&#xff09; 頁面組件 &#xff08;配置路由規則時使用的組件&#xff09;復用組件&#xff08;多個組件中都使用到的組件&#xff09; 存放目錄 分類開來的…

Llama模型家族之拒絕抽樣(Rejection Sampling)(二)均勻分布簡介

LlaMA 3 系列博客 基于 LlaMA 3 LangGraph 在windows本地部署大模型 &#xff08;一&#xff09; 基于 LlaMA 3 LangGraph 在windows本地部署大模型 &#xff08;二&#xff09; 基于 LlaMA 3 LangGraph 在windows本地部署大模型 &#xff08;三&#xff09; 基于 LlaMA…

ssti模板注入

一、Flask應用 1、介紹 定義 Flask&#xff1a;是一個使用Python編寫的輕量級web應用框架。Flask基于Werkzeug WSGI工具包和Jinja2模板引擎。 特點 良好的文檔、豐富的插件、包含開發服務器和調試器、集成支持單元測試、RESTful請求調度、支持安全cookies、基于Unicode。 …

手機短信刪除怎么恢復?快速找回的3個秘密武器

手機&#xff0c;這個我們每天離不開的小玩意兒&#xff0c;有時候也會讓我們頭疼不已。比如&#xff0c;你一不小心&#xff0c;或者為了清理點空間&#xff0c;就把那些重要的短信給刪了。這些短信可能是你和好友的深夜聊天&#xff0c;或者是重要的工作信息。一旦刪除&#…

人工智能就業方向有哪些?

人工智能就業方向有哪些? 隨著人工智能技術的不斷發展&#xff0c;其應用領域也越來越廣泛。對于想要進入人工智能領域的年輕人來說&#xff0c;選擇一個合適的職業方向是至關重要的。今天給大家介紹六個熱門的人工智能就業方向&#xff0c;分別是機器學習工程師、自然語言處理…