日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

pthread_join函数

發(fā)布時(shí)間:2023/11/30 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 pthread_join函数 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

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

作用:阻塞等待線程退出,獲取線程退出狀態(tài)。其作用對(duì)應(yīng)進(jìn)程中 waitpid() 函數(shù)。

成功:0;失敗:錯(cuò)誤號(hào) ??strerror函數(shù)

參數(shù):thread:線程ID (注意:不是指針);retval:存儲(chǔ)線程結(jié)束狀態(tài)。

對(duì)比記憶:在wait回收子進(jìn)程時(shí),子進(jìn)程exit或return返回的值即為status的值(int類型),wait函數(shù)第一個(gè)形參為回收進(jìn)程的pid,第二個(gè)形參為&status(int *類型指針);對(duì)于回收子線程時(shí),子線程退出的值(pthread_exit函數(shù),或return返回的值)都為void *類型,則pthread_join函數(shù)的第一個(gè)形參為線程ID(pthread_t類型),第二個(gè)形參為void **類型。

調(diào)用該函數(shù)的線程將掛起等待,直到idthread的線程終止。thread線程以不同的方法終止,通過(guò)pthread_join得到的終止?fàn)顟B(tài)是不同的,總結(jié)如下:

  • 如果thread線程通過(guò)return返回,retval所指向的單元里存放的是thread線程函數(shù)的返回值(即void *指針);
  • 如果thread線程被別的線程調(diào)用pthread_cancel異常終止掉,retval所指向的單元里存放的是常數(shù)PTHREAD_CANCELED。
  • 如果thread線程是自己調(diào)用pthread_exit終止的,retval所指向的單元存放的是傳給pthread_exit的參數(shù)(即void *指針),其實(shí)1與3是等效的。
  • 如果對(duì)thread線程的終止?fàn)顟B(tài)不感興趣,可以傳NULL給retval參數(shù)。
  • 對(duì)應(yīng)于僵尸進(jìn)程,也是存在僵尸線程。因此,在線程結(jié)束時(shí),也需要對(duì)線程進(jìn)行回收以釋放僵尸線程所占用的資源。對(duì)進(jìn)程的回收有區(qū)別的就是,一個(gè)進(jìn)程中的所有線程都是可以互相回收的,即不是只能由主控線程回收子線程,兄弟線程之間也可以回收。一次pthread_join只能回收一個(gè)線程。回收線程時(shí)也可以不關(guān)心線程結(jié)束時(shí)的狀態(tài),pthread_join函數(shù)的參數(shù)傳NULL即可,此時(shí)不關(guān)心線程結(jié)束時(shí)的狀態(tài),只是將其回收并釋放線程所占用的資源。

    //循環(huán)創(chuàng)建n個(gè)子線程,并回收這n個(gè)子線程

    #include <stdio.h> #include <pthread.h> #include <string.h> #include <unistd.h> #include <stdlib.h>typedef struct {int a;char b;char str[10]; }exit_t; //返回值為一個(gè)結(jié)構(gòu)體void *ftn( void *arg ) {int s;exit_t *retval; //retval的地址在棧空間,但是retval本身卻位與堆空間(heap),malloc所分配的。retval=(exit_t *)malloc( sizeof(exit_t) ); //必須用malloc分配,不能用線程棧空間s=(int)arg; //注意只能傳值,不能傳地址(用于判別是哪個(gè)線程)if( s<=1 ){retval->a=10;retval->b='a';strcpy(retval->str,"zsx");}if( s>1 && s<=3 ){retval->a=20;retval->b='b';strcpy(retval->str,"rgf");}if( s>3 ){retval->a=30;retval->b='c';strcpy(retval->str,"zy");}printf("I am %dth thread, and my ID is %lu.\n",s+1,pthread_self( ));pthread_exit((void *)retval); //或者 return (void *)retval; 兩者等價(jià)! }int main(int argc, char *argv[ ]) {int n=5, i, ret;if( argc==2 )n=atoi(argv[1]);pthread_t tid[n];for(i=0;i<n;i++){ret=pthread_create(&tid[i],NULL,ftn,(void *)i); //注意只能傳值,不能傳地址,因?yàn)榈刂穼?duì)應(yīng)的i值會(huì)變化if( ret!=0){fprintf(stderr,"pthread_create error: %s\n",strerror(ret));exit(1);}}for(i=0;i<n;i++) //回收每個(gè)子線程{exit_t *re; //re位于主控線程的棧空間,但是re本身的值為子線程傳給它的值。ret=pthread_join( tid[i],(void **)&re);if( ret!=0){fprintf(stderr,"pthread_join error: %s\n",strerror(ret));exit(1);}printf("the %dth thread: a=%d, b=%c, str=%s.\n",i+1,re->a,re->b,re->str);free(re); //注意必須釋放malloc分配的空間,防止內(nèi)存泄漏re = NULL; //置空,防止使用幽靈指針}printf("In main: the PID is %d, and the TID is %lu.\n",getpid( ),pthread_self( ));pthread_exit((void *)1); }

    [root@localhost 01_pthread_test]# ./ptrd_join

    I am 4th thread, and my ID is 4124101440.

    I am 2th thread, and my ID is 4140886848.

    I am 1th thread, and my ID is 4149279552.

    I am 5th thread, and my ID is 4115708736.

    I am 3th thread, and my ID is 4132494144.

    the 1th thread: a=10, b=a, str=zsx.

    the 2th thread: a=10, b=a, str=zsx.

    the 3th thread: a=20, b=b, str=rgf.

    the 4th thread: a=20, b=b, str=rgf.

    the 5th thread: a=30, b=c, str=zy.

    In main: the PID is 10415, and the TID is 4151490816.

    分析討論:

  • 強(qiáng)調(diào)一點(diǎn):子線程的返回值為void *指針,其指針?biāo)赶虻牡刂繁仨毼挥谌謪^(qū)或者malloc分配的空間,不能位于用戶棧空間;
  • 之所以子線程的返回值以及線程函數(shù)ftn的形參都要為void *類型,這是為了方便可以傳遞任何數(shù)據(jù)類型;
  • 其實(shí)回收子線程的返回值的方式有很多種:a.第一種方式:上述程序中,exit_t *retval; 然后直接返回retval這個(gè)地址給主控線程,但是地址不能是用戶棧空間,因此用malloc函數(shù)分配空間后,再賦值返回;b.第二種方式:也可以exit_t retval,即直接返回retval本身這個(gè)值,即return (void *)retval; 主控線程中:exit_t *re; (exit_t)re即可,但是不建議這樣做,兼容性不高。這種方法類似于上面的i傳參方式;c.第三種方式:還是按值傳遞,即利用主控線程中的pthread_create函數(shù)中的最后一個(gè)參數(shù),將值傳給子線程,然后讓子線程返回回來(lái),即:主控線程: exit_t *re=(exit_t *)malloc( sizeof(exit_t) ), 然后(void *)re作為其最后一個(gè)參數(shù)傳遞給子線程的arg參數(shù),則子線程中:(exit_t *)arg,然后給arg賦值,最后(void *)arg返回即可!
  • 注意在線程函數(shù)中:pthread_exit((void *)retval);不能寫為:pthread_exit((void *)&retval);? 同樣的錯(cuò)誤,即這樣相當(dāng)于傳遞的是子線程用戶棧空間的地址。
  • 總結(jié)

    以上是生活随笔為你收集整理的pthread_join函数的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。