個人主頁:chian-ocean
文章專欄-Linux
前言:
POSIX線程(Pthreads) 是一種在 POSIX 標準下定義的線程庫,它為多線程編程提供了統一的接口,主要用于 UNIX 和類 UNIX 系統(如 Linux、MacOS 和 BSD 等)。POSIX 線程(Pthreads)允許程序在多個處理器上并行運行,從而提高應用程序的性能,尤其在多核處理器環境中。
監控線程的bash
while :; do ps -aL | head -1 ; ps -aL | grep thread ; sleep 1;done
線程的控制
- 與線程有關的函數構成了?個完整的系列,絕?多數函數的名字都是以
pthread_
打頭的 - 要使?這些函數庫,要通過引?頭?
pthread.h
- 鏈接這些線程函數庫時要使?編譯器命令的“-lpthread”選項
線程的創建(pthread_create
)
#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine)(void *), void *arg);
參數解析:
pthread_t *thread
:指向pthread_t
類型的變量,這個變量將存儲新線程的 ID。const pthread_attr_t *attr
:指向pthread_attr_t
類型的指針,它包含了新線程的屬性(如棧大小、調度策略等)。如果傳入NULL
,則使用默認屬性。void *(*start_routine)(void *)
:這是一個指向線程執行函數的指針,該函數接收一個void*
類型的參數,并返回void*
類型的結果。void *arg
:這是傳遞給start_routine
函數的參數,允許你向線程傳遞數據。
示例:
#include<iostream>
#include<unistd.h>
#include<pthread.h> using namespace std; // 線程函數
void* mythread(void* args)
{// 創建一個循環,子線程會打印 6 次for(int i = 0; i < 6; i++) {sleep(1); // 讓線程睡眠 1 秒鐘,模擬任務的執行cout << "Child Thread" << endl; // 打印“Child Thread”,表示子線程在運行}return nullptr;
}// 主函數
int main()
{pthread_t tid; // 定義一個線程ID變量// 創建子線程,線程的執行函數是 mythread,其他參數為默認值pthread_create(&tid, nullptr, mythread, nullptr);// 主線程執行,循環 6 次for(int i = 0; i < 6; i++) {cout << "Main Thread" << endl; // 打印“Main Thread”,表示主線程在運行sleep(1); // 讓主線程睡眠 1 秒鐘}// 等待子線程完成執行pthread_join(tid, nullptr); // 阻塞等待 tid 線程執行完畢return 0; // 程序正常退出
}
pthread_create()
:用于創建一個新的線程,mythread
是新線程的執行函數。該函數接受參數nullptr
,表示沒有傳遞任何參數給線程。pthread_join(tid, nullptr)
:等待線程tid
執行完成,pthread_join
阻塞主線程,直到子線程執行完畢。
打印結果:
線程退出
pthread_join
#include <pthread.h>
int pthread_join(pthread_t thread, void **retval);
參數說明:
pthread_t thread
:要等待結束的線程 ID。void **retval
:用于存儲線程返回值的指針。如果不需要返回值,可以將其設置為NULL
。
功能描述:
pthread_join()
函數使得調用該函數的線程(通常是主線程)阻塞,直到指定的線程(由thread
參數指定)執行完畢。- 當線程結束后,系統會回收該線程的資源。如果
retval
不為NULL
,線程的返回值將被存儲在retval
指向的位置。
示例:
#include<iostream>
#include<unistd.h>
#include<pthread.h>using namespace std;// 子線程的執行函數
void* mythread(void*args)
{// 循環6次,每次打印一次信息,并且每次暫停1秒for(int i = 0 ; i < 6 ;i++) {sleep(1); // 休眠1秒鐘cout << "Child Thread is running ...." << endl; // 輸出子線程運行的提示}// 返回一個值100,并強制轉換為 void* 類型return (void*)100;
}int main()
{pthread_t tid; // 定義一個線程ID變量// 創建子線程,傳入 mythread 函數作為線程執行的函數,參數為 nullptrpthread_create(&tid, nullptr, mythread, nullptr);// 主線程運行6次,每次輸出一次信息,并且每次暫停1秒for(int i = 0 ; i < 6 ;i++) {cout << "Main Thread is running .." << endl; // 輸出主線程運行的提示sleep(1); // 休眠1秒鐘}void* retval; // 聲明一個指向 void 的指針,用于接收子線程的返回值// 等待子線程結束,并將子線程的返回值存儲到 retval 中pthread_join(tid, &retval);// 輸出子線程的返回值,將其強制轉換為整數類型并輸出cout << (int64_t)retval << endl; // 輸出子線程的返回值,轉換為整數return 0;
}
程序流程:
- 并發輸出:主線程和子線程的輸出交替進行,打印在終端上時會交替顯示 “Main Thread is running …” 和 “Child Thread is running …”。
- 同步:主線程通過
pthread_join()
等待子線程完成,并獲取子線程的返回值。 - 線程返回值:子線程通過
return (void*)100
返回一個void*
類型的值,主線程通過pthread_join()
捕獲該返回值并輸出。
打印:
pthread_exit
#include <pthread.h>
void pthread_exit(void *retval);
參數說明:
retval
:這是一個指針,線程退出時可以返回的值。該值可以被其他線程通過pthread_join
獲取,用來傳遞線程的退出狀態或其他信息。- 注意:
retval
可以是任何類型的指針,通常是一個線程退出的狀態信息。
示例:
#include<iostream>
#include<unistd.h>
#include<pthread.h>using namespace std;void* mythread(void* args) // 線程函數
{// 子線程執行的操作,循環輸出 "Child Thread is running ...."for (int i = 0; i < 6; i++) {sleep(1); // 每次休眠1秒cout << "Child Thread is running ...." << endl;}// 輸出結束前的信息cout << "Child Pthread_exit" << endl;// 使用 pthread_exit 顯式退出線程并返回一個狀態碼 100pthread_exit((void*)100);// 這一行代碼不會被執行到,因為 pthread_exit 已經退出線程return (void*)100;
}int main()
{pthread_t tid; // 聲明一個線程標識符// 創建線程pthread_create(&tid, nullptr, mythread, nullptr);// 主線程執行的操作for (int i = 0; i < 6; i++) {cout << "Main Thread is running .." << endl;sleep(1); // 每次休眠1秒}// 主線程休眠,確保子線程有時間執行sleep(8); // 等待子線程執行完畢// 主線程結束前輸出信息cout << "main return " << endl;return 0; // 程序結束
}
程序流程:
- 程序運行時,子線程和主線程會交替輸出 “Child Thread is running …” 和 “Main Thread is running …”。
- 主線程執行完成它的循環后,調用
sleep(8)
來等待子線程的執行。此時,子線程已經執行完它的循環,并通過pthread_exit
顯式退出。 - 由于沒有在主線程中調用
pthread_join()
,主線程并沒有等待子線程完成,它只是通過sleep(8)
暫停一段時間,確保子線程有足夠的時間結束。
打印:
pthread_cancal
#include <pthread.h>
int pthread_cancel(pthread_t thread);
參數說明:
pthread_t thread
:目標線程的線程 ID(TID),即你希望取消的線程。
功能描述:
pthread_cancel
用于向指定的線程發送取消請求。調用此函數后,目標線程會接收到取消請求,并在合適的時機響應取消請求。
返回值:
- 返回 0 表示成功,其他返回值表示失敗,通常是因為無法取消線程(如線程已經結束等)。
示例:
#include<iostream>
#include<unistd.h>
#include<pthread.h>
#include<vector>
#include<string>
using namespace std;// Hex函數,用于將整數轉換為十六進制字符串
string Hex(int data)
{char buff[1034] = {0};// snprintf用于將整數data轉換為十六進制字符串snprintf(buff,sizeof(buff),"0x%x",data);return buff;
}// 線程函數,打印每個線程的整數值
void* mythread(void* args)
{// 將傳入的參數指針轉換為整型指針int* i = (int*)args;while(true) // 無限循環,模擬線程的持續運行{sleep(1); // 每次休眠1秒cout << "thread: " << *i << endl; // 輸出線程ID(即傳遞給線程的值)}return (void*)100; // 返回一個指針類型的值,通常線程退出時返回狀態
}int main()
{// 定義一個 vector 來存儲線程IDvector<pthread_t> th;// 創建4個線程for(int i = 0; i < 4; i++){pthread_t tid; // 定義一個線程ID變量// 創建線程,將線程ID、線程函數(mythread)以及傳遞給線程的參數(i的地址)傳入pthread_create(&tid, nullptr, mythread, &i);// 將線程ID添加到線程容器中th.push_back(tid);}cout << "ready calcel" << endl;sleep(3); // 休眠3秒,等待線程輸出// 取消每個創建的線程for(int i = 0; i < th.size(); i++){cout <<"calcel: thread " << i <<endl; // 輸出正在取消的線程編號pthread_cancel(th[i]); // 取消對應的線程}sleep(1); // 稍等1秒,確保線程能夠響應取消請求cout << "main return "<<endl; // 輸出主線程返回信息return 0; // 程序結束
}
程序流程:
-
** 主線程創建子線程:**主線程使用
pthread_create()
創建 4 個子線程,每個子線程打印傳遞給它的整數值(即循環中的i
),并在每秒打印一次。 -
**線程輸出:**每個線程在無限循環中每秒輸出
thread: <value>
,其中<value>
是它收到的整數(傳遞給線程的i
)。 -
**主線程等待:**主線程在創建完線程后,休眠 3 秒,允許線程輸出信息。
-
**取消線程:**主線程在 3 秒后調用
pthread_cancel()
來取消所有 4 個線程,每個線程被取消后,它會終止執行(線程的退出取決于它們在什么地方被取消)。 -
**程序結束:**主線程輸出
"main return"
并結束,程序執行完畢。
打印:
線程分離
#include <pthread.h>
int pthread_detach(pthread_t thread);
參數:
thread
:要設置為分離狀態的線程 ID。
功能描述
- 功能描述:
pthread_detach
用于將一個線程設置為 分離狀態。當線程被設置為分離狀態后,線程在完成執行時會自動釋放資源,而不需要其他線程顯式地調用pthread_join()
來清理線程資源。
示例:
#include<iostream>
#include<unistd.h>
#include<pthread.h>
#include<vector>
#include<string>
using namespace std;// Hex函數:將整數轉換為十六進制字符串
string Hex(int data)
{char buff[1034] = {0};snprintf(buff, sizeof(buff), "0x%x", data); // 將整數以十六進制格式轉換成字符串return buff;
}// 線程函數
void* mythread(void* args)
{pthread_detach(pthread_self()); // 將當前線程設置為分離狀態int* i = (int*)args; // 將傳入的參數指針轉換為整型指針int n = 3;// 循環打印線程編號(傳遞給線程的值),共打印3次while(n--){sleep(1); // 每次循環休眠1秒cout << "thread: " << *i << endl; // 輸出線程的編號}return (void*)100; // 線程返回值
}int main()
{vector<pthread_t> th; // 用于存儲線程ID的容器cout << "線程的創建" << endl;// 創建4個線程for(int i = 0; i < 4; i++){pthread_t tid;pthread_create(&tid, nullptr, mythread, &i); // 創建線程并傳遞 i 的地址作為參數th.push_back(tid); // 將創建的線程ID加入到線程容器中}sleep(10); // 主線程休眠10秒,確保所有子線程能運行完cout << "main return " << endl;return 0; // 主程序結束
}
程序執行流程:
- 主線程通過
pthread_create
創建 4 個子線程,每個子線程都會執行mythread
函數。 - 每個子線程會打印 3 次其編號(線程的參數),并在每次打印后休眠 1 秒。
- 主線程休眠 10 秒,以確保子線程有足夠的時間打印信息。
- 每個子線程在完成執行后會自動退出并釋放資源,因為它們是分離線程(調用了
pthread_detach
)。 - 主線程輸出 “main return” 并結束。
打印:
- 以上的代碼沒有實現同步,可能會導致錯亂打印。