【C++ 语言】线程 ( 线程创建方法 | 线程标识符 | 线程属性 | 线程属性初始化 | 线程属性销毁 | 分离线程 | 线程调度策略 | 线程优先级 | 线程等待 )
文章目錄
- I 線程創(chuàng)建方法
- II 線程執(zhí)行函數
- III 線程標識符
- IV 線程屬性
- V 線程屬性 1 ( 分離線程 | 非分離線程 )
- VI 線程屬性 2 ( 線程調度策略 )
- VII 線程屬性 3 ( 線程優(yōu)先級設置 )
- VIII 線程等待
- IX 互斥鎖
- X 線程代碼示例
I 線程創(chuàng)建方法
1. 線程創(chuàng)建方法函數原型 : int pthread_create(pthread_t *tidp, const pthread_attr_t *attr, (void*)(*start_rtn)(void*), void *arg);
2. pthread_create 方法的 4 個參數 ;
- 參數 1 ( pthread_t *tidp ) : 線程標識符指針 , 該指針指向線程標識符 ;
- 參數 2 ( const pthread_attr_t *attr ) : 線程屬性指針 ;
- 參數 3 ( (void*)(*start_rtn)(void*) ) : 線程運行函數指針 , start_rtn 是一個函數指針 , 其參數和返回值類型是 void* 類型 ;
- 參數 4 ( void *arg ) : 參數 3 中的線程運行函數的參數 ;
3. 返回值說明 :
- 線程創(chuàng)建成功 , 返回 0 ;
- 線程創(chuàng)建失敗 , 返回 錯誤代碼 ;
4. 關于函數指針參數的說明 : C++ 中函數指針類型是 void *(PTW32_CDECL *start) (void *)
- 函數的參數類型是 void* 指針 ;
- 函數的返回值類型 void* 指針 ;
5. 函數多參數方案 : 如果線程執(zhí)行的函數有多個參數 , 可以使用結構體 , 類進行封裝 ;
6. 線程屬性 : 創(chuàng)建線程時 , 給線程指定屬性 pthread_attr_t 是結構體類型 ;
7. 代碼示例 :
/*線程創(chuàng)建方法函數原型 : int pthread_create(pthread_t *tidp, const pthread_attr_t *attr, (void*)(*start_rtn)(void*), void *arg);該方法需要提供四個參數 ;參數 1 ( pthread_t *tidp ) :線程標識符指針 , 該指針指向線程標識符 ;參數 2 ( const pthread_attr_t *attr ) : 線程屬性指針 ;參數 3 ( (void*)(*start_rtn)(void*) ) : 線程運行函數指針 , start_rtn 是一個函數指針 , 其參數和返回值類型是 void* 類型參數 4 ( void *arg ) : 參數 3 中的線程運行函數的參數 ;返回值 :線程創(chuàng)建成功 , 返回 0 ;線程創(chuàng)建失敗 , 返回 錯誤代碼 ;關于函數指針參數 : C++ 中函數指針類型是 void *(PTW32_CDECL *start) (void *) ,函數的參數類型是 void* 指針函數的返回值類型 void* 指針函數多參數方案 : 如果線程執(zhí)行的函數有多個參數 , 可以使用結構體 , 類進行封裝線程屬性 : 創(chuàng)建線程時 , 給線程指定屬性 pthread_attr_t 是結構體類型*///函數指針 函數名 和 &函數名 都可以作為函數指針pthread_create(&pid , &attribute, pthread_function, hello);II 線程執(zhí)行函數
1. 線程執(zhí)行函數的要求 : C++ 中規(guī)定線程執(zhí)行函數的函數指針類型是 void *(PTW32_CDECL *start) (void *) ;
2. 函數作用 : 將該函數的指針作為線程創(chuàng)建方法 pthread_create 的第三個參數 ;
3. 參數處理 : 在線程創(chuàng)建時 , 傳入參數 , 將該參數轉為 char* 字符串指針類型 , 將其打印出來 ;
4. 代碼示例 :
/*定義線程中要執(zhí)行的方法將該函數的指針作為線程創(chuàng)建方法 pthread_create 的第三個參數C++ 中規(guī)定線程執(zhí)行函數的函數指針類型是 void *(PTW32_CDECL *start) (void *) */ void* pthread_function(void* args) {//延遲 100 ms 執(zhí)行//_sleep(100);//指針類型轉換 : 將 void* 轉為 char*// 使用 static_cast 類型轉換標識符char* hello = static_cast<char*>(args);//打印參數cout << "pthread_function 線程方法 執(zhí)行 參數 : " << hello << endl;return 0; }III 線程標識符
1. 線程標識符 : pthread_t 類型 , 用于聲明線程的 ID ;
2. 類型本質 : 該類型是一個結構體 ;
typedef struct {void * p; /* Pointer to actual object */unsigned int x; /* Extra information - reuse count etc */ } ptw32_handle_t;typedef ptw32_handle_t pthread_t;3. 代碼示例 : 聲明線程標識符 , 下面的代碼是在棧內存中聲明線程標識符 , pthread_create 方法中需要傳入指針 , 這里使用取地址符獲取其指針 ;
//線程標識符 , 這里需要傳入指針 , 因此這里使用 & 取地址符獲取其地址當做指針變量pthread_t pid;IV 線程屬性
1. 線程屬性 : pthread_attr_t 表示線程屬性類型 , 查看其類型聲明 , 得到如下代碼 , pthread_attr_t 類型是一個指針類型 ;
typedef struct pthread_attr_t_ * pthread_attr_t;2. 線程屬性聲明 : 線程屬性類型是一個指針 , 初始化時其值是隨機值 , 是個野指針 , 這里將其設置為 0 ;
pthread_attr_t attribute = 0;3. 線程屬性的初始化和銷毀 : 該線程屬性需要先進行初始化和銷毀;
- ① 線程屬性初始化 : 函數原型 int pthread_attr_init(pthread_attr_t *attr); ; 初始化線程屬性時 , 對屬性進行了默認配置 ;
- ② 線程屬性銷毀 : 函數原型 int pthread_attr_destroy(pthread_attr_t *attr); ;
4. 二維指針參數 :
- ① 參數說明 : 線程初始化和銷毀方法傳入 pthread_attr_t * 類型的參數 , pthread_attr_t 類型是指針 , pthread_attr_t * 是 二維指針 ; 初始化時 , 肯定要創(chuàng)建一個有實際意義的線程屬性結構體 , 將 attribute 二維指針指向線程屬性結構體指針 ;
- ② 指向指針的指針意義 : 在傳遞時可以 在函數內部 修改指針指向的地址 ;
5. 代碼示例 :
/*線程屬性結構體變量該線程屬性需要先進行初始化和銷毀;線程屬性初始化方法 : int pthread_attr_init(pthread_attr_t *attr);線程屬性銷毀方法 : int pthread_attr_destroy(pthread_attr_t *attr);線程屬性類型定義 : typedef struct pthread_attr_t_ * pthread_attr_t;pthread_attr_t 其本質是一個指針 ; pthread_attr_t attribute 聲明后 , 該指針是野指針 , 需要將其設置為 0 ;*/pthread_attr_t attribute = 0;//初始化線程屬性, 此處的參數是指針的指針 , 該指針指向 0 地址 ; // 初始化時 , 肯定要創(chuàng)建一個有實際意義的線程屬性結構體 , 將 attribute 二維指針 指向結構體指針// 指向指針的指針意義 : 在傳遞時可以在函數內部修改指針指向的地址 ; //初始化線程屬性時 , 對屬性進行了默認配置 ;pthread_attr_init(&attribute);V 線程屬性 1 ( 分離線程 | 非分離線程 )
1. 線程的默認屬性 : 線程創(chuàng)建后 , 默認是非分離線程 ;
2. 非分離線程 :
- ① 特點 : 非分離線程允許在其它線程中 , 來等待另外線程執(zhí)行完畢 ;
- ② 表現 : 創(chuàng)建線程后 , 線程執(zhí)行 , 如果調用 pthread_join 函數 , 其作用是等待 pthread_function 線程函數執(zhí)行完畢 ;
3. 分離線程 : 不能被其它線程操作 , 如調用 pthread_join 函數 , 無法等待該分離線程執(zhí)行完畢 ;
4. 非分離線程 與 分離線程 比較 :
- ① 設置非分離線程屬性 : 先執(zhí)行完線程內容 , 等待線程執(zhí)行完畢后 , 才執(zhí)行 pthread_join 后的代碼 ;
- ② 設置分離線程屬性 : pthread_join 等待線程執(zhí)行完畢是無效的 , 主線程會繼續(xù)向后執(zhí)行 , 不會等待線程執(zhí)行完畢
5. 分離線程不經常使用 : 一般情況下是不經常將線程設置為分離線程 , 如果設置了 , 那么該線程就無法進行控制 ;
6. 設置線程為分離線程代碼示例 :
pthread_attr_setdetachstate(&attribute, PTHREAD_CREATE_DETACHED);VI 線程屬性 2 ( 線程調度策略 )
該功能在 Android , Linux 上可以使用 , 在 Visual Studio 中暫時無法測試
1. 線程調度策略 : 線程是需要搶占 CPU 資源進行執(zhí)行的 , 調度策略就是設置搶占 CPU 的策略 ;
2. SCHED_FIFO 策略 :
- ① 調度機制 : 先創(chuàng)建的線程先執(zhí)行 , CPU 一旦占用則一直占用 ;
- ② CPU 資源釋放時機 : 當有更高優(yōu)先級的任務出現或線程執(zhí)行完畢 , CPU 資源才會釋放 ;
- ③ 串行執(zhí)行 : 如果兩個線程都是 SCHED_FIFO 策略 , 并且優(yōu)先級一樣 , 那么兩個線程一起執(zhí)行的話 , 要先后執(zhí)行 , 無法同時執(zhí)行;
3. SCHED_RR 策略 :
- ① 調度機制 : 時間片輪轉 , 系統(tǒng)為不同的線程分配不同的時間段 , 指定的線程只有在指定的時間段內才能使用 CPU 資源 ;
- ② 并行執(zhí)行 : 如果兩個線程都是 SCHED_RR 策略 , 并且優(yōu)先級一樣 , 那么兩個線程一起執(zhí)行的話 , 兩個線程同時執(zhí)行 ;
4. 調度策略設置方法 :
- ① 函數原型 : int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy);
- ② 參數 1 ( pthread_attr_t *attr ) : 線程屬性對象 ;
- ③ 參數 2 ( int policy ) : 調度策略 ;
VII 線程屬性 3 ( 線程優(yōu)先級設置 )
該功能在 Android , Linux 上可以使用 , 在 Visual Studio 中暫時無法測試
1. 線程優(yōu)先級 : 優(yōu)先級是一個數值 , 數值越大 , 優(yōu)先級越高 , 系統(tǒng)在進行線程調度時 , 優(yōu)先給優(yōu)先級高的線程分配資源 , 優(yōu)先級高的先執(zhí)行 ;
2. 線程優(yōu)先級類型 : 優(yōu)先級是 sched_param 結構體變量 , 在 sched_param 結構體中只有一個成員sched_priority ;
struct sched_param {int sched_priority;};3. 優(yōu)先級取值范圍 : 該范圍與調度策略有關 , 可以獲取該調度策略優(yōu)先級的最大最小值 ;
- ① 獲取 SCHED_FIFO 策略的最大優(yōu)先級 :
- ② 獲取 SCHED_FIFO 策略的最小優(yōu)先級 :
4. 設置線程優(yōu)先級代碼示例 :
//獲取 SCHED_FIFO 策略的最大優(yōu)先級int max_priority_of_fifo = sched_get_priority_max(SCHED_FIFO);//獲取 SCHED_FIFO 策略的最小優(yōu)先級int min_priority_of_fifo = sched_get_priority_min(SCHED_FIFO);//聲明調度參數結構體sched_param param;//設置調度參數結構體的 sched_priority 成員param.sched_priority = max_priority_of_fifo;//設置線程優(yōu)先級pthread_attr_setschedparam(&attribute, ¶m);VIII 線程等待
1. 線程等待方法 :
- ① 函數作用 : 等待線程結束 , 用于線程間同步操作 ;
- ② 函數原型 : int pthread_join(pthread_t thread, void **retval); ;
- ③ 參數 1 ( pthread_t thread ) : 線程標識符 , 要等待哪個線程結束 ;
- ④ 參數 2 ( void **retval ) : 被等待線程的返回值 ;
2. 代碼示例 :
//pthread_join : 等待線程結束// 等線程執(zhí)行完畢后 , 在執(zhí)行下面的內容pthread_join(pid, 0);IX 互斥鎖
【C++ 語言】pthread_mutex_t 互斥鎖
X 線程代碼示例
1. 代碼示例 :
// 005_Thread.cpp: 定義應用程序的入口點。 //#include "005_Thread.h" #include <pthread.h>//引入隊列的頭文件 #include <queue>using namespace std;/*定義線程中要執(zhí)行的方法將該函數的指針作為線程創(chuàng)建方法 pthread_create 的第三個參數C++ 中規(guī)定線程執(zhí)行函數的函數指針類型是 void *(PTW32_CDECL *start) (void *) */ void* pthread_function(void* args) {//延遲 100 ms 執(zhí)行//_sleep(100);//指針類型轉換 : 將 void* 轉為 char*// 使用 static_cast 類型轉換標識符char* hello = static_cast<char*>(args);//打印參數cout << "pthread_function 線程方法 執(zhí)行 參數 : " << hello << endl;return 0; }/*互斥鎖 :聲明 : 先聲明互斥鎖初始化 : 在進行初始化操作銷毀 : 使用完畢后 , 要將該互斥鎖銷毀 */ pthread_mutex_t mutex_t;//聲明一個隊列變量 // 該變量是全局變量 // 該變量要在不同的線程中訪問 , 用于展示線程同步 queue<int> que;/*操作線程方法 : 參數和返回值都是 void* 類型互斥鎖使用 : 多個線程對一個隊列進行操作 , 需要使用互斥鎖將該隊列鎖起來 , pthread_mutex_lock使用完畢后在進行解鎖 , pthread_mutex_unlock該類型的鎖與 Java 中的 synchronized 關鍵字一樣 , 屬于悲觀鎖其作用是通過 mutex 互斥鎖 , 將上鎖與解鎖之間的代碼進行同步 */ void* queue_thread_fun(void* args) {//先用互斥鎖上鎖pthread_mutex_lock(&mutex_t);if (!que.empty()) {//打印隊列中的第一個元素printf("獲取 que 隊列第一個數據 : %d\n", que.front());//將隊列首元素彈出que.pop();}else {printf("獲取 que 隊列為空\n");}//操作完畢后, 解鎖pthread_mutex_unlock(&mutex_t);return 0; }/*如果 8 個線程同時讀取隊列中的信息 , 會出現程序崩潰在多線程環(huán)境下 , 對隊列進 queue_thread 行操作 , queue_thread 是線程不安全的這里需要加鎖 , 進行 線程同步的操作 */ int main() {//初始化互斥鎖pthread_mutex_init(&mutex_t, 0);//向其中加入 5 個int數據for (size_t i = 0; i < 5; i++) {que.push(i);cout << "放入數據 : " << i << endl;}//創(chuàng)建多個線程操作 queue_thread 隊列pthread_t pids[8];for (size_t i = 0; i < 8; i++) {//創(chuàng)建線程pthread_create(&pids[i], 0, queue_thread_fun, 0);}//銷毀互斥鎖pthread_mutex_destroy(&mutex_t);return 0; }int main2() {cout << "Hello CMake。" << endl;// I. 測試 POSIX 線程方法pthread_self();// II //線程標識符 , 這里需要傳入指針 , 因此這里使用 & 取地址符獲取其地址當做指針變量pthread_t pid;char* hello = "Hello Thread";/*線程屬性結構體變量該線程屬性需要先進行初始化和銷毀;線程屬性初始化方法 : int pthread_attr_init(pthread_attr_t *attr);線程屬性銷毀方法 : int pthread_attr_destroy(pthread_attr_t *attr);線程屬性類型定義 : typedef struct pthread_attr_t_ * pthread_attr_t;pthread_attr_t 其本質是一個指針 ; pthread_attr_t attribute 聲明后 , 該指針是野指針 , 需要將其設置為 0 ;*/pthread_attr_t attribute = 0;//初始化線程屬性, 此處的參數是指針的指針 , 該指針指向 0 地址 ; // 初始化時 , 肯定要創(chuàng)建一個有實際意義的線程屬性結構體 , 將 attribute 二維指針 指向結構體指針// 指向指針的指針意義 : 在傳遞時可以在函數內部修改指針指向的地址 ; //初始化線程屬性時 , 對屬性進行了默認配置 ;pthread_attr_init(&attribute);//常用屬性 1 : //非分離線程 ;// 線程創(chuàng)建后 , 默認是非分離線程 ; // 創(chuàng)建線程后 , 線程執(zhí)行 , 如果調用 pthread_join 函數 , 其作用是等待 pthread_function 線程函數執(zhí)行完畢 ; // 非分離線程允許在其它線程中 , 來等待另外線程執(zhí)行完畢 ; //分離線程 : // 不能被其它線程操作 , 如調用 pthread_join 函數 , 無法等待該分離線程執(zhí)行完畢 ; /*設置線程屬性為 分離線程如果沒有設置分離線程時 , 先執(zhí)行完線程內容 , 等待線程執(zhí)行完畢后 , 才執(zhí)行 pthread_join 后的代碼如果設置了分離線程屬性 , pthread_join 等待線程執(zhí)行完畢是無效的 , 主線程會繼續(xù)向后執(zhí)行 , 不會等待線程執(zhí)行完畢 因此打印出的內容是 先打印 "線程執(zhí)行完畢" , 然后才打印線程方法中的內容不經常使用 : 一般情況下是不經常將線程設置為分離線程 , 如果設置了 , 那么該線程就無法進行控制*/pthread_attr_setdetachstate(&attribute, PTHREAD_CREATE_DETACHED);/*常用屬性 2 : 線程的調度策略該功能在 Android , Linux 上可以使用 , 在 Visual Studio 中暫時無法測試線程是需要搶占 CPU 資源進行執(zhí)行的 , 調度策略就是設置搶占 CPU 的策略調度策略 : SCHED_FIFO 策略 : 先創(chuàng)建的線程先執(zhí)行 , CPU 一旦占用則一直占用 , CPU 資源釋放時機 : 當有更高優(yōu)先級的任務出現或線程執(zhí)行完畢 , CPU 資源才會釋放串行執(zhí)行 : 如果兩個線程都是 SCHED_FIFO 策略 , 并且優(yōu)先級一樣 , 那么兩個線程一起執(zhí)行的話 , 要先后執(zhí)行 , 無法同時執(zhí)行; SCHED_RR 策略 : 時間片輪轉 , 系統(tǒng)為不同的線程分配不同的時間段 , 指定的線程只有在指定的時間段內才能使用 CPU 資源并行執(zhí)行 : 如果兩個線程都是 SCHED_RR 策略 , 并且優(yōu)先級一樣 , 那么兩個線程一起執(zhí)行的話 , 兩個線程同時執(zhí)行 調度策略設置方法 : 函數原型 : int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy);參數 1 ( pthread_attr_t *attr ) : 線程屬性對象參數 2 ( int policy ) : 調度策略 *//*常用屬性 3 : 優(yōu)先級設置該功能在 Android , Linux 上可以使用 , 在 Visual Studio 中暫時無法測試優(yōu)先級是一個數值 , 數值越大 , 優(yōu)先級越高 , 系統(tǒng)在進行線程調度時 , 優(yōu)先給優(yōu)先級高的線程分配資源 , 優(yōu)先級高的先執(zhí)行 ; 優(yōu)先級是 sched_param 結構體變量 , 在 sched_param 結構體中只有一個成員sched_priority ; struct sched_param {int sched_priority;};優(yōu)先級設置方法 : pthread_attr_setschedparam優(yōu)先級取值范圍 : 該范圍與調度策略有關 , 可以獲取該調度策略優(yōu)先級的最大最小值下面有獲取 SCHED_FIFO 的最高和最低優(yōu)先級取值*///獲取 SCHED_FIFO 策略的最大優(yōu)先級int max_priority_of_fifo = sched_get_priority_max(SCHED_FIFO);//獲取 SCHED_FIFO 策略的最小優(yōu)先級int min_priority_of_fifo = sched_get_priority_min(SCHED_FIFO);//聲明調度參數結構體sched_param param;//設置調度參數結構體的 sched_priority 成員param.sched_priority = max_priority_of_fifo;//設置線程優(yōu)先級pthread_attr_setschedparam(&attribute, ¶m);/*線程創(chuàng)建方法函數原型 : int pthread_create(pthread_t *tidp, const pthread_attr_t *attr, (void*)(*start_rtn)(void*), void *arg);該方法需要提供四個參數 ;參數 1 ( pthread_t *tidp ) :線程標識符指針 , 該指針指向線程標識符 ;參數 2 ( const pthread_attr_t *attr ) : 線程屬性指針 ;參數 3 ( (void*)(*start_rtn)(void*) ) : 線程運行函數指針 , start_rtn 是一個函數指針 , 其參數和返回值類型是 void* 類型參數 4 ( void *arg ) : 參數 3 中的線程運行函數的參數 ;返回值 :線程創(chuàng)建成功 , 返回 0 ;線程創(chuàng)建失敗 , 返回 錯誤代碼 ;關于函數指針參數 : C++ 中函數指針類型是 void *(PTW32_CDECL *start) (void *) ,函數的參數類型是 void* 指針函數的返回值類型 void* 指針函數多參數方案 : 如果線程執(zhí)行的函數有多個參數 , 可以使用結構體 , 類進行封裝線程屬性 : 創(chuàng)建線程時 , 給線程指定屬性 pthread_attr_t 是結構體類型*///函數指針 函數名 和 &函數名 都可以作為函數指針pthread_create(&pid , &attribute, pthread_function, hello);//pthread_join : 等待線程結束// 等線程執(zhí)行完畢后 , 在執(zhí)行下面的內容pthread_join(pid, 0);cout << " 線程執(zhí)行完畢 " << endl;//銷毀線程屬性pthread_attr_destroy(&attribute);return 0; }2. 執(zhí)行結果 :
放入數據 : 0 放入數據 : 1 放入數據 : 2 放入數據 : 3 放入數據 : 4 獲取 que 隊列第一個數據 : 0 獲取 que 隊列第一個數據 : 1 獲取 que 隊列第一個數據 : 2 獲取 que 隊列第一個數據 : 3 獲取 que 隊列第一個數據 : 4D:\002_Project\006_Visual_Studio\005_Thread\out\build\x64-Debug\005_Thread\005_Thread.exe (進程 1852)已退出,返回代碼為: 0。 若要在調試停止時自動關閉控制臺,請啟用“工具”->“選項”->“調試”->“調試停止時自動關閉控制臺”。 按任意鍵關閉此窗口...總結
以上是生活随笔為你收集整理的【C++ 语言】线程 ( 线程创建方法 | 线程标识符 | 线程属性 | 线程属性初始化 | 线程属性销毁 | 分离线程 | 线程调度策略 | 线程优先级 | 线程等待 )的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【C++ 语言】Visual Studi
- 下一篇: 【Android 应用开发】View 与