在Linux中,線程的應用還是比較廣泛的,同時,線程退出的返回值對線程來說,也是一種比較客觀的數據傳輸。
本文主要是在Linux中進行測試,不涉及windows等其他OS。
1. 線程的創建
pthread_create(pthread_t *thread,const pthread_attr_t *attr,void*(*start_routine)(void*),void* arg);
首先,參數一:代表的是線程的pid地址
參數二:代表的是是否設置線程的分離屬性,這里設置為NULL,不分離
參數三:代表的是線程的處理函數
參數四:線程處理函數的參數列表,這里設置為NULL,不帶參數內容
(注意,這里主要是創建線程的作用)
2. 線程的等待
pthread_join(pthread_t thread, void **retval)
首先: 參數一: 代表線程pid
參數二: 代表線程的返回值 (--> 這個是本文討論的重點參數)
3. 例子設計:
這里設計兩個線程,線程一是通過一般的return返回,作為線程的返回值;線程二,則是使用線程庫中的pthread_exit()函數
來進行返回參數。
首先,函數pthread_exit(void *retval)
這里的retval就是線程退出的時候返回給主線程的值,也是今天需要討論的情況。
例子如下:
1 #include <pthread.h> 2 #include <stdio.h> 3 #include <string.h> 4 #include <unistd.h> 5 #include <errno.h> 6 7 #define PTHREAD_NUM 2 8 9 void *sendData(void *arg) 10 { 11 static int count = 2; 12 13 pthread_exit((void*)(&count)); 14 15 } 16 17 18 void *recvData(void *arg) 19 { 20 static int count = 3; 21 22 return (void *)(&count); 23 24 25 } 26 27 28 int main(int argc,char *argv[]) 29 { 30 pthread_t pid[PTHREAD_NUM]; 31 int retPid; 32 int *ret; 33 int *dat; 34 35 36 if((retPid = pthread_create(&pid[0],NULL,sendData,NULL)) != 0) 37 { 38 perror("create pid first failed"); 39 return -1; 40 } 41 42 43 if((retPid = pthread_create(&pid[1],NULL,recvData,NULL)) != 0) 44 { 45 perror("create pid second failed"); 46 return -1; 47 } 48 49 50 if(pid[0] != 0) 51 { 52 53 pthread_join(pid[0],(void**)&ret); 54 printf("get thread 0 message: %d\n",*ret); 55 } 56 57 58 if(pid[1] != 0) 59 { 60 pthread_join(pid[1],(void**)&dat); 61 printf("get thread 1 message: %d\n",*dat); 62 } 63 64 65 return 0; 66 }
講解:這里的最主要的問題就是我們需要進行強制類型的轉換。
首先,對於pthread_exit這個函數,他的返回參數的類型為void *,現在我們返回的是一個“整數”,因此必須將其進行轉換
1. 先轉換為整形指針,count為int類型,那么&count為int*類型,同樣為了保持匹配,這里本人使用顯式的調用,直接寫作為
&count,其實這個表明了現在變成了一個int的指針,這個時候與void*匹配的話,需要進行強制轉換,也就是代碼中的
(void*)(&count);
2. return這個關鍵字進行返回值得時候,同樣也是需要進行強制類型的轉換。線程函數的返回類型是void*,那么對於count這個
整形數值來說,必須進行轉換為void的指針類型(即void*),因此有:(void*)((int*)&count);
3. 對於接收返回值的線程函數pthread_join來說,有兩個作用。其一就是等待線程結束,其二就是獲取線程結束的時候返回的數值
是什么。所以,對於它的參數類型是void**這種二級指針的,我們可以把它分解為一級指針,這樣就比較容易進行理解和調用。本文
討論的是整數,那么設置接收返回值得為一個整形指針,這樣就感覺給二級指針void**降階了。
4. 對接收返回值得參數進行強制轉換,這里定義接收返回值得類型是int*,因此轉化為void**,也就是(void**)&ret,因為&ret就已
經說明了現在的類型為int**,然后顯式地轉為void**即可
5. 另外,本文在返回整數數值的時候使用到了static這個關鍵字,這是因為必須確定返回值的地址是不變的。對於count變量而言,在
內存上來講,屬於在棧區開辟的變量,那么在調用結束的時候,必然是釋放內存空間的,相對而言,這時候,就沒辦法找到count所代表
內容的地址空間。這就是為什么很多人在看到swap交換函數的時候,為什么寫成swap(int,int)是沒有辦法進行交換的,所以,如果我
們需要修改傳過來的參數的話,必須是要使用這個參數的地址,或者是一個變量本身是不變的內存地址空間,這樣才可以進行修改,否則,
修改失敗或者返回值是隨機值。
結果:
上述的結果表明,返回的數值是我們所要求的數值,是正確的。讀者可以試着返回的是一個字符串,這樣就比返回是一個整數
更加簡單明了。說到底,整篇文章也就是強制轉換的結果。讀者可以更加深入地自己去理解