国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統(tǒng) > Linux > 正文

Linux 下子線程的 pthread_cleanup_push() 和 pthread_cleanup_pop() 研究

2024-06-28 13:19:03
字體:
供稿:網(wǎng)友
linux 下子線程的 pthread_cleanup_push() 和 pthread_cleanup_pop() 研究

線程退出前可能有一些清理工作,但是這部分代碼又不會放到線程主體部分,就需要掛接一個或者幾個線程“清潔工”來做這部分事情。需要這對兄弟:

#include<pthread.h>void pthread_cleanup_push(void (*rtn)(void *), void *arg);void pthread_cleanup_pop(int execute);

顯然pthread_cleanup_push() 是掛接 清理函數(shù)的,它的返回值類型為 void,有兩個入口參數(shù),第一個參數(shù)是清理函數(shù)函數(shù)指針,第二個參數(shù)是傳給清理函數(shù)的 typeless pointer 。

另一個兄弟 pthread_cleanup_pop() 是來觸發(fā)清理函數(shù)的,是按照相反的順序來觸發(fā)清理函數(shù)的。而如果它的入口參數(shù) execute 為0值,則對應的清理函數(shù)并沒有真正的執(zhí)行。

例如下面這個例子:

  1 /****************************************************************  2 #     File Name: thread_cleanup3.c  3 #     Author   : lintex9527  4 #     E-Mail   : lintex9527@yeah.net  5 #  Created Time: Sat 22 Aug 2015 03:25:09 PM HKT  6 #  Purpose     : 測試清理函數(shù)的觸發(fā)順序,以及執(zhí)行與否。  7 #  Outline     :   8 #  Usage       :   9 #               -------------------------------------------------- 10 #  Result      :  11 #               -------------------------------------------------- 12 *****************************************************************/ 13 #include <stdio.h> 14 #include <stdlib.h> 15 #include <pthread.h> 16  17 /* 線程傳遞給 清理函數(shù) 的參數(shù)結(jié)構(gòu)體 */ 18 struct argtype{ 19     int a,b; 20     int result; 21 }; 22  23 void PRint_argtype(const char *str, struct argtype *p) 24 { 25     printf("%s/n", str); 26     printf("    a = %d, b = %d/n", p->a, p->b); 27     printf("    result = %d/n", p->result); 28 } 29  30 /* for thread 1 */ 31 struct argtype entity1 = { 32     .a = 50, 33     .b = 5, 34     .result = 11 35 }; 36  37 /* 以下是3個清理函數(shù) */ 38 void cleanup_add(void *arg) 39 { 40     struct argtype *p = (struct argtype *)arg; 41     p->result = p->a + p->b; 42     print_argtype("cleanup [add]", p); 43     //pthread_exit((void *)p->result); 44 } 45  46 void cleanup_minus(void *arg) 47 { 48     struct argtype *p = (struct argtype *)arg; 49     p->result = p->a - p->b; 50     print_argtype("cleanup [minus]", p); 51     //pthread_exit((void *)p->result); 52 } 53  54  55 void cleanup_times(void *arg) 56 { 57     struct argtype *p = (struct argtype *)arg; 58     p->result = p->a * p->b; 59     print_argtype("cleanup [times]", p); 60     //pthread_exit((void *)p->result); 61 } 62  63 /* 子線程1函數(shù),臨時地改變了entity1結(jié)構(gòu)體中成員值,檢查清理函數(shù)執(zhí)行點 */ 64 void* thr1_fun(void *arg) 65 {  66     printf("Now thread1 [%lu] start:/n", pthread_self()); 67  68     pthread_cleanup_push(cleanup_times, (void *)&entity1);  // cleanup_times 69     entity1.a = 20; 70     entity1.b = 2; 71     pthread_cleanup_push(cleanup_minus, (void *)&entity1);  // cleanup_minus 72     pthread_cleanup_push(cleanup_add, (void *)&entity1);   // cleanup_add 73     pthread_cleanup_pop(3);  // cleanup_add 74  75     entity1.a = 30; 76     entity1.b = 3; 77     pthread_cleanup_pop(1);  // cleanup_minus 78  79     entity1.a = 40; 80     entity1.b = 4; 81     pthread_cleanup_pop(1);  // cleanup_times 82  83     entity1.a = 80; 84     entity1.b = 8; 85     pthread_exit((void *)entity1.result); 86 } 87  88  89 int main(void) 90 { 91     int err; 92     pthread_t tid1; 93     void *tret; 94  95     err = pthread_create(&tid1, NULL, thr1_fun, NULL); 96     err = pthread_join(tid1, &tret); 97     if (err != 0) 98     { 99         perror("pthread_join");100         return -1;101     }102 103     printf("In main get result [%d] from thread %lu/n", tret, tid1);104     print_argtype("main:", &entity1);105 106     return 0;107 }

執(zhí)行結(jié)果:

$ ./thread_cleanup3.exe Now thread1 [140090204903168] start:cleanup [add]    a = 20, b = 2    result = 22cleanup [minus]    a = 30, b = 3    result = 27cleanup [times]    a = 40, b = 4    result = 160In main get result [160] from thread 140090204903168main:    a = 80, b = 8    result = 160

順序測試

在這個例子中,我把 pthread_cleanup_pop(int execute) 中的 execute 都設(shè)定為非零值,測試3個清理函數(shù)的調(diào)用順序,

注冊的順序是: cleanup_times --> cleanup_minus --> cleanup_add

調(diào)用的順序是: cleanup_add --> cleanup_minus --> cleanup_times

的的確確是按照相反的順序調(diào)用的。

執(zhí)行點測試

為了測試每一個清理函數(shù)的執(zhí)行點,我在每一個pthread_cleanup_pop() 之前都修改了 結(jié)構(gòu)體 entity1 的域 a,b。經(jīng)過比對發(fā)現(xiàn)每一個 pthread_cleanup_push() 和 pthread_cleanup_pop() 形成一個 pairs,因為它們是基于宏實現(xiàn)的,pthread_cleanup_push() 中包含了一個“{”,而 pthread_cleanup_pop() 中包含了一個“}” 和前面的對應,因此它們必須成對的出現(xiàn),否則代碼通不過編譯。經(jīng)過檢查和對比,發(fā)現(xiàn)每一個 pairs 雖然在代碼形式上互相嵌套,但是它們的執(zhí)行沒有互相嵌套。即在執(zhí)行最外面的 cleanup_times() 并沒有遞歸調(diào)用 cleanup_minus() 繼而遞歸調(diào)用 cleanup_times()。

因此在處理最外面的 cleanup_times() 時屏蔽了從 pthread_cleanup_push(cleanup_minus, xxx) 到 pthread_cleanupo_pop(yyy) (與 cleanup_minus 對應的) 部分的代碼。

而在處理 cleanup_minus() 時屏蔽了從 pthread_cleanup_push(cleanup_add, xxx) 到 pthread_cleanup_pop(yyy) (與 cleanup_add 對應的) 部分的代碼。

因為 pop 順序和 push 順序是相反的,那么從第一個 pop 的順序開始執(zhí)行: cleanup_add --> cleanup_minus --> cleanup_times.

但是每一次執(zhí)行 cleanup_xxx 的參數(shù)為什么會不一樣的呢?是從哪里開始變化的呢?

是從線程函數(shù)入口上到下,一直到 pthread_cleanup_pop() 部分的參數(shù)對當前的 cleanup_xxx() 函數(shù)有效。在當前 pthread_cleanup_pop() 下面的語句是對后面一個 pop() 函數(shù)起作用的。

如下面這張圖:

左邊的指示線條表征的是每一個 push 入棧的清理函數(shù)可訪問的資源區(qū);

右邊的雙箭頭線表征的是 push / pop 對子,雖然在代碼形式上有嵌套,但是在函數(shù)執(zhí)行上并不會嵌套執(zhí)行。

根據(jù)分析,

entity1.a , entity1.b 傳遞給 cleanup_add() 函數(shù)的值是 20 , 2;

entity1.a , entity1.b 傳遞給 cleanup_minus() 函數(shù)的值是 30, 3;

entity1.a , entity1.b 傳遞給 cleanup_times() 函數(shù)的值是 40, 4;

而最終在 main thread 中可以訪問到的 entity1.a, entity1.b 的值是 80 , 8 。那個時候已經(jīng)沒有 清理函數(shù) cleanup_xxx() 去訪問 entity1 結(jié)構(gòu)體了。

另外,我原本在清理函數(shù)內(nèi)部添加了 pthread_exit() 函數(shù),這會出現(xiàn)什么情況呢?比如取消 cleanup_times() 函數(shù)里 pthread_exit() 之前的注釋,編譯運行結(jié)果如下:

$ ./thread_cleanup3.exe Now thread1 [140415830189824] start:now cleanup_add.cleanup [add]    a = 20, b = 2    result = 22now cleanup_minus.cleanup [minus]    a = 30, b = 3    result = 27now cleanup_times.cleanup [times]    a = 40, b = 4    result = 160In main get result [160] from thread 140415830189824main:    a = 40, b = 4    result = 160

對比之前,發(fā)現(xiàn)在 main thread 中的 a,b 值是40, 4 ,這和子線程退出點有關(guān),子線程沒有走到下面這一步:

    entity1.a = 40;    entity1.b = 4;    printf("now cleanup_times./n");    pthread_cleanup_pop(1); // cleanup_times-------------------------------------------------------------------// 下面沒有執(zhí)行    entity1.a = 80;    entity1.b = 8;    printf("thread 1 is exit.../n");    pthread_exit((void *)entity1.result);

說明提前使用 pthread_exit() 那么各個函數(shù)訪問的資源就更受限。

但是在2個及以上的清理函數(shù)中添加 pthread_exit() ,會導致線程不斷地調(diào)用 清理函數(shù),進入死機狀態(tài)。

總結(jié)就是不要在清理函數(shù)中添加 pthread_exit() 。


發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 资中县| 湟源县| 盐亭县| 垣曲县| 河曲县| 鹰潭市| 陇川县| 福州市| 临高县| 板桥市| 阳西县| 荆门市| 桑日县| 宣威市| 江油市| 哈尔滨市| 香河县| 佛坪县| 新兴县| 伊金霍洛旗| 固始县| 尉氏县| 临夏县| 淮南市| 花莲市| 尼木县| 柞水县| 于田县| 忻州市| 治多县| 阿克苏市| 曲松县| 永新县| 曲靖市| 梅河口市| 阿拉善右旗| 大姚县| 保康县| 西吉县| 苏州市| 苏州市|