例子詳細解析:
一. pthread_create()與pthread_join()函數
1 #include <pthread.h> 2 int pthread_join(pthread_t thread, 3 void **retval);
1. pthread_join函數作用
pthread_join函數作用是在一個線程中以阻塞的方式等待另一個線程(線程標識符為thread)的退出。如果等待的進程已經結束,那么該函數會立即返回。
retval是用戶定義的指針,用來存儲被等待線程的返回值。
返回值: 0 -- 成功,失敗 -- 錯誤號errno
2. pthread_join的應用
使一個線程等待另一個線程的結束
代碼中如果沒有pthread_join主線程會很快結束,從而從而合整個進程線束,從而使創建的線程沒有機會執行就結束了,在主線程加入pthread_join后,主線程會阻塞等待直到(被等待的)線程結束后,主線程自己才結束,從而使創建的線程有機會執行
3. 一個線程不能被多個線程等待,否則第一個接收到信號的線程成功返回,其余調用 pthread_join 的線程則返回錯誤代碼ESRCH。
1 #include <pthread.h> 2 int pthread_create(pthread_t *thread, 3 const pthread_attr_t *attr, 4 void *(*start_routine) (void *), 5 void *arg);
1. pthread_create函數的作用
創建一個線程,成功時返回0,錯誤時返回errno。
thread:被創建線程的標識符,pthread_join使用這個標識符來等待該線程的結束。
attr: 設置線程的屬性,可以為NULL
第三個參數是線程函數的入口地址
arg: 傳遞給線程的參數,當要傳遞給線程的參數有多個時,可以使用結構體.
具體例子
#ifdef HAVE_CONFIG_H #include <config.h> #endif #include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <string.h> // 參數結構體 struct argument { int num; char string[30]; }; // 聲明兩個線程函數 void *thread1_func( void * ); void *thread2_func( void * ); int main(int argc, char *argv[]) { //定義兩個線程標識符 pthread_t thread1, thread2; //定義用來接收兩個線程退出后的返回值,用作pthread_join的第二個參數 void *thread1_return, *thread2_return; //傳遞的參數結構體 struct argument arg1, arg2; int i; int wait_thread_end; //判斷線程退出成功與否 //參數結構體值初始化 arg1.num = 1949; strcpy( arg1.string, "中華人民共和國" ); arg2.num = 2012; strcpy( arg2.string, "建國63周年" ); // 創建兩個線程 pthread_create(&thread1, NULL, thread1_func, (void*)&arg1 ); pthread_create( &thread2, NULL, thread2_func, (void*)&arg2 ); for( i = 0; i < 2; i++ ) { printf("我是最初的進程!\n"); sleep(2); //主統線程睡眠,調用其他線程 } //等待第一個線程退出,並接收它的返回值(返回值存儲在thread1_return) wait_thread_end = pthread_join( thread1, &thread1_return ); if( wait_thread_end != 0 ) { printf("調用 pthread_join 獲取線程1的返回值出現錯誤!\n"); } else { printf("調用 pthread_join 成功!線程1退出后的返回值是 %d\n", (int)thread1_return); } //等待第二個線程退出,並接收它的返回值(返回值存儲在thread2_return) wait_thread_end = pthread_join( thread2, &thread2_return); if( wait_thread_end != 0 ) { printf("調用 pthread_join 獲取線程2的返回值出現錯誤!\n"); } else { printf("調用 pthread_join 成功!線程2退出后的返回值是 %d\n",(int)thread2_return ); } return EXIT_SUCCESS; } /** *線程1函數實現 */ void *thread1_func( void *arg ) { int i; struct argument *arg_thread1; // 接收傳遞過來的參數結構體 arg_thread1 = ( struct argument * )arg; for( i = 0; i < 3; i++) { printf( "我來自線程1,傳遞給我的參數是 %d, %s\n", arg_thread1->num, arg_thread1->string); sleep(2); // 投入睡眠,調用其它線程 } return (void *)123; } void *thread2_func( void *arg ) { int i; struct argument *arg_thread2; // 接收傳遞過來的參數結構體 arg_thread2 = ( struct argument * )arg; for( i = 0; i < 3; i++) { printf( "我來自線程2,傳遞給我的參數是 %d, %s\n", arg_thread2->num, arg_thread2->string); sleep(2); // 投入睡眠,調用其它線程 } return (void *)456; }
例子中要請注意的地方:
void *thread1_func( void *arg )
{
...
return (void*)123;
}
void *thread2_func( void *arg )
{
...
return (void*)456;
}
1. 在線程函數中thread1_func()和thread2_func()中,最后一句return語句中,對返回的值要進行類型轉換(轉換成(void *)),返回值的類型要與線程函數的聲明和定義的返回值類型一致。
2. 兩個線程函數的返回值均為一個指針(把一個整數轉換成(void*)返回)。該指針存儲在pthread_join()的第三個參數中,在這兩個函數中等價於
&thread1_return = thread1_func((void*)&arg1);
&thread2_return = thread2_func((void*)&arg2);
其中,&thread1_return是pthread_join的第二個參數,在前面函數解析中說過,pthread_join(phtread_t thread, void **retval)函數的第二個參數retval可以存儲線程的返回值。該返回值直接存儲在&thread1_return和&thread2_return,此時thread1_return和thread2_return值就是線程1和線程2函數的返回值(void *)類型。所以(int)thread1_return和(int)thread2_return就是該函數的返回值內容。由定義(void *thread1_return, *thread2_return)可以看出,thread1_return和thread2_return中兩個指針,也就是說,這兩個指針所存儲的地址已經被兩個線程的返回值所覆蓋。
