(6)執行緒的連線和分離
①執行緒連線
[1]int pthread_join(pthread_t thread, void **retval);
pthread_t: 等待的執行緒尚未退出,那麼 pthread_join 的呼叫執行緒就會陷入阻塞。
retval: 接收返回值
· 等待的執行緒尚未退出,那麼pthread_join 的呼叫執行緒就會陷入阻塞。
· 等待的執行緒已經退出,那麼pthread_join 函式會將執行緒的退出值(void* 型別存放到retval)指標指向的位置。
1.pthread_join 函式之所以能夠判斷是否死鎖和連線操作是否被其他執行緒捷足先登,是因為目標執行緒的控制結構體 struct pthread 中,存在如下成
員變數,記錄了該執行緒的連線者。
2.直接連線自己, 或者A連線B, B又連線A
1.程序之間的等待只能是父程序等待子程序,
2.執行緒組內的成員是對等的關係,執行緒組內的任一執行緒都可其他執行緒進行連線(join)
3.程序等待可以等待一個程序組內的所有執行緒(waipid)
4.執行緒的連線操作只能單獨連線某個具體的執行緒: 當庫函式嘗試連線( join )私自建立的執行緒時,發現已經被連線過了,就會返回EINVAL 錯誤。
1.已經退出的執行緒,其空間沒有被釋放,仍然在程序的地址空間之內。
2.新建立的執行緒,沒有複用剛才退出的執行緒的地址空間。
==> 造成資源洩漏
3.當執行緒組內的其他執行緒呼叫pthread_join連線退出執行緒時,內部會呼叫__free_tcb函式,該函式會負責釋放退出執行緒的資源。
4.縱然呼叫了pthread_join,也並沒有立即呼叫munmap來釋放掉退出執行緒的棧,它們是被後建的執行緒複用了。(再次反覆建立執行緒,分配執行緒棧會影響效能)
②執行緒分離
[1]設定執行緒為可分離狀態
int pthread_detach(pthread_t thread);
thread: 要分離的執行緒標識ID
1.如果其他執行緒並不關心執行緒的返回值,連線操作就會變成一種負擔: 不連線會造成執行緒資源不釋放(洩漏記憶體)
2.被設定為分離的執行緒: 執行緒退出時,系統自動將執行緒相關的資源釋放掉,無須等待連線。
3.可以是執行緒組內其他執行緒對目標執行緒進行分離,也可以是執行緒自己執行 pthread_detach 函式,將自身設定成已分離的狀態
pthread_detach(pthread_self()) // 將本執行緒設定為可分離狀態
4.如果執行緒處於已分離的狀態,其他執行緒嘗試連線執行緒時,會返回 EINVAL 錯誤。
5.所謂已分離: 是指執行緒退出後,系統會自動釋放執行緒資源。
[2]建立執行緒時, 將執行緒的屬性設定為已分離(建立已分離執行緒) // 執行緒退出後, 系統自動回收資源
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
thread_create(&tid, &attr, func,arg);
// 獲取執行緒分離狀態
int pthread_attr_setdetachstate(pthread_attr_t *attr,int detachstate);
int pthread_attr_getdetachstate(pthread_attr_t *attr,int *detachstate);
③.示例程式碼:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <strings.h>
#include <string.h>
#include <sys/types.h>
#include <errno.h>
#include <pthread.h>
#include <sys/syscall.h>
#include <sys/prctl.h>
int ret = 123;
void *start_routime1(void *arg) /* 主執行緒關心執行緒退出的返回值 */
{
printf("start_routime1\n");
pthread_exit(&ret);// 將返回值的首地址儲存在了pret所指向的地方
}
void *start_routime2(void *arg) /* 主執行緒不關心執行緒退出的返回值 */
{
printf("start_routime2\n");
pthread_detach(pthread_self()); // 設定為分離狀態, 執行緒退出後自動釋放資源
}
/* 這是一個已分離的執行緒, 執行緒退出後系統自動釋放資源 */
void *start_routime3(void *arg) /* 主執行緒不關心執行緒退出的返回值 */
{
printf("start_routime3\n");
}
int main(int argc, char **argv)
{
pthread_t sub_id1, sub_id2, sub_id3;
int detachstate;
pthread_attr_t attr;
void *pret;
printf("\n-------------------1--------------------------------\n");
// 建立的執行緒1預設為可連線狀態
if(pthread_create(&sub_id1, NULL, start_routime1, NULL))
perror("pthread_create1 err");
pthread_join(sub_id1, &pret);
printf("pret = %d\n", *(int *)pret); // 必須對該執行緒進行連線,才能回收該執行緒的資源
printf("\n-------------------2--------------------------------\n");
// 建立的執行緒2預設為可連線狀態
if(pthread_create(&sub_id2, NULL, start_routime2, NULL))
perror("pthread_create2 err");
sleep(1);
// 執行緒2設定了分離狀態, 會自動釋放資源, 不用進行連線
// 或者在主執行緒中將執行緒2設定為分離狀態
// pthread_detach(sub_id2);
printf("\n------------------3---------------------------------\n");
// 建立detach執行緒, 執行緒退出後, 系統會自動回收資源
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED); // 設定即將建立的執行緒屬性為已分離
pthread_attr_getdetachstate(&attr, &detachstate); // 獲取執行緒的分離狀態
if (detachstate == PTHREAD_CREATE_DETACHED)
printf("pthread 3 PTHREAD_CREATE_DETACHED\n");
else if (detachstate == PTHREAD_CREATE_JOINABLE)
printf("pthread 3 PTHREAD_CREATE_JOINABLE\n");
if(pthread_create(&sub_id3, &attr, start_routime3, NULL)); // 建立執行緒
perror("pthread_create3 err");
memset(&attr, 0, sizeof(attr));
detachstate = 0;
return 0;
}
/* 執行結果:
[email protected]_hua_shu$ gcc -o t join_detach.c -lpthread
[email protected]_hua_shu$ ./t
-------------------1--------------------------------
start_routime1
pret = 123
-------------------2--------------------------------
start_routime2
------------------3---------------------------------
pthread 3 PTHREAD_CREATE_DETACHED
pthread_create3 err: Success
*/