生活随笔
收集整理的這篇文章主要介紹了
linux——线程(2)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
文章目錄
- 1.pthread_join 函數
- 2.pthread_detach 函數
- 3.pthread_cancel 函數
- 4.終止線程方式
- 5.控制原語對比
- 6.線程屬性
- 7.線程屬性初始化
- 8.線程的分離狀態
- 9.線程使用注意事項
1.pthread_join 函數
阻塞等待線程退出,獲取線程退出狀態 其作用,對應進程中 waitpid() 函數。
int pthread_join(pthread_t thread
, void **retval
); 成功:
0;失敗:錯誤號
參數:thread:線程 ID (【注意】:不是指針);retval:存儲線程結束狀態。
對比記憶:
進程中:main 返回值、exit 參數–>int;等待子進程結束 wait 函數參數–>int *
線程中:線程主函數返回值、pthread_exit–>void *;等待線程結束 pthread_join 函數參數–>void **
#include<stdio.h>
#include<pthread.h>
#include <stdlib.h>
#include<unistd.h>void* print(void* arg
){sleep(1);printf("in print:pthread id=%lu,pid=%u\n",pthread_self(),getpid());pthread_exit((void*)100);
}
int main()
{pthread_t tid
;int ret
;int* retval
;printf("in main1:pthread id=%lu,pid=%u\n",pthread_self(),getpid());ret
=pthread_create(&tid
,NULL,print
,NULL);sleep(1);if(ret
!=0){printf("pthread_create error\n");exit(1);}printf("in main1:pthread id=%lu,pid=%u\n",pthread_self(),getpid());pthread_join(tid
,(void**)&retval
);printf("tid=%lu,retval=%d\n",tid
,(int)retval
);pthread_exit(NULL);
}
zhaoxr@zhaoxr
-ThinkPad
-E450
:~/pthread$
./pthread_join
in main1
:pthread id
=140071725627200,pid
=36916
in main1
:pthread id
=140071725627200,pid
=36916
in print
:pthread id
=140071725623040,pid
=36916
tid
=140071725623040,retval
=100
2.pthread_detach 函數
實現線程分離
int pthread_detach(pthread_t thread
); 成功:
0;失敗:錯誤號
線程分離狀態:指定該狀態,線程主動與主控線程斷開關系。線程結束后,其退出狀態不由其他線程獲取,而直接自己自動釋放。網絡、多線程服務器常用。
進程若有該機制,將不會產生僵尸進程。 僵尸進程的產生主要由于進程死后,大部分資源被釋放,一點殘留資源仍存于系統中,導致內核認為該進程仍存在。
也可使用 pthread_create 函數參 2(線程屬性)來設置線程分離。
#include<stdio.h>
#include<pthread.h>
#include <stdlib.h>
#include<unistd.h>
#include<string.h>void* print(void* arg
){sleep(1);printf("執行子線程:pthread id=%lu,pid=%u\n",pthread_self(),getpid());pthread_exit((void*)100);
}
int main()
{pthread_t tid
;int ret
,err
;int* retval
;ret
=pthread_create(&tid
,NULL,print
,NULL);if(ret
!=0){printf("pthread_create error\n");exit(1);}printf("開始回收\n");err
=pthread_join(tid
,(void**)&retval
);if(err
!=0){fprintf(stderr,"pthread_join error:%s\n",strerror(err
));printf("回收失敗\n");}else{printf("回收成功\n");}pthread_exit(NULL);
}
zhaoxr@zhaoxr
-ThinkPad
-E450
:~/pthread$
./pthread_detach
開始回收
執行子線程
:pthread id
=140291944003328,pid
=36996
回收成功
#include<stdio.h>
#include<pthread.h>
#include <stdlib.h>
#include<unistd.h>
#include<string.h>void* print(void* arg
){sleep(1);printf("執行子線程:pthread id=%lu,pid=%u\n",pthread_self(),getpid());pthread_exit((void*)100);
}
int main()
{pthread_t tid
;int ret
,err
;int* retval
;ret
=pthread_create(&tid
,NULL,print
,NULL);if(ret
!=0){printf("pthread_create error\n");exit(1);}pthread_detach(tid
);printf("開始回收\n");err
=pthread_join(tid
,(void**)&retval
);if(err
!=0){fprintf(stderr,"pthread_join error:%s\n",strerror(err
));printf("回收失敗\n");}else{printf("回收成功\n");}pthread_exit(NULL);
}
zhaoxr@zhaoxr
-ThinkPad
-E450
:~/pthread$
./pthread_detach
開始回收
pthread_join error
:Invalid argument
回收失敗
執行子線程
:pthread id
=139917284878080,pid
=37018
3.pthread_cancel 函數
殺死(取消)線程 其作用,對應進程中 kill() 函數。
int pthread_cancel(pthread_t thread
); 成功:
0;失敗:錯誤號
【注意】:線程的取消并不是實時的,而有一定的延時。需要等待線程到達某個取消點(檢查點)。
類似于玩游戲存檔,必須到達指定的場所(存檔點,如:客棧、倉庫、城里等)才能存儲進度。
殺死線程也不是立刻就能完成,必須要到達取消點。
取消點:是線程檢查是否被取消,并按請求進行動作的一個位置。
通常是一些系統調用 creat,open,pause,close,read,write… 執行命令 man 7 pthreads 可以查看具備這些取消點的系統調用列表。
也可參閱 APUE.12.7 取消選項小節。
可粗略認為一個系統調用(進入內核)即為一個取消點。
如線程中沒有取消點,可以通過調用 pthread_testcancel函數自行設置一個取消點。
被取消的線程, 退出值定義在Linux的pthread庫中。常數PTHREAD_CANCELED的值是-1。
可在頭文件pthread.h中找到它的定義:#define PTHREAD_CANCELED ((void *) -1)。
因此當我們對一個已經被取消的線程使用 pthread_join回收時,得到的返回值為-1。
4.終止線程方式
總結:終止某個線程而不終止整個進程,有三種方法:
從線程主函數 return。這種方法對主控線程不適用,從 main 函數 return 相當于調用 exit。一個線程可以調用 pthread_cancel 終止同一進程中的另一個線程。線程可以調用 pthread_exit 終止自己。
5.控制原語對比
進程線程
| fork | pthread_create |
| exit | pthread_exit |
| wait | pthread_join |
| kill | pthread_cancel |
| getpid | pthread_self 命名空間 |
6.線程屬性
本節作為指引性介紹,linux 下線程的屬性是可以根據實際項目需要,進行設置,之前我們討論的線程都是采用線程的默認屬性,默認屬性已經可以解決絕大多數開發時遇到的問題。
如我們對程序的性能提出更高的要求那么需要設置線程屬性,比如可以通過設置線程棧的大小來降低內存的使用,增加最大線程個數。
typedef struct
{int etachstate
; int schedpolicy
; struct sched_param schedparam
; int inheritsched
; int scope
; size_t guardsize
; int stackaddr_set
; void* stackaddr
; size_t stacksize
;
} pthread_attr_t
;
主要結構體成員:
線程分離狀態線程棧大小(默認平均分配)線程棧警戒緩沖區大小(位于棧末尾) 參 APUE.12.3 線程屬性
屬性值不能直接設置,須使用相關函數進行操作,初始化的函數為 pthread_attr_init,這個函數必須在pthread_create 函數之前調用。之后須用 pthread_attr_destroy 函數來釋放資源。
線程屬性主要包括如下屬性:作用域(scope)、棧尺寸(stack size)、棧地址(stack address)、優先級(priority)、分離的狀態(detached state)、調度策略和參數(scheduling policy and parameters)。
默認的屬性為非綁定、非分離、缺省的堆棧、與父進程同樣級別的優先級
7.線程屬性初始化
注意:應先初始化線程屬性,再 pthread_create 創建線程
初始化線程屬性
int pthread_attr_init(pthread_attr_t
*attr
); 成功:
0;失敗:錯誤號
銷毀線程屬性所占用的資源
int pthread_attr_destroy(pthread_attr_t
*attr
); 成功:
0;失敗:錯誤號
8.線程的分離狀態
線程的分離狀態決定一個線程以什么樣的方式來終止自己。
非分離狀態:線程的默認屬性是非分離狀態,這種情況下,原有的線程等待創建的線程結束。只有當 pthread_join()函數返回時,創建的線程才算終止,才能釋放自己占用的系統資源。
分離狀態:分離線程沒有被其他的線程所等待,自己運行結束了,線程也就終止了,馬上釋放系統資源。應該根據自己的需要,選擇適當的分離狀態。
線程分離狀態的函數:
設置線程屬性,分離
or 非分離
int pthread_attr_setdetachstate(pthread_attr_t
*attr
, int detachstate
);
獲取程屬性,分離
or 非分離
int pthread_attr_getdetachstate(pthread_attr_t
*attr
, int *detachstate
);
參數: attr:已初始化的線程屬性
detachstate: PTHREAD_CREATE_DETACHED(分離線程)
PTHREAD _CREATE_JOINABLE(非分離線程)
這里要注意的一點是,如果設置一個線程為分離線程,而這個線程運行又非常快,它很可能在 pthread_create函數返回之前就終止了,它終止以后就可能將線程號和系統資源移交給其他的線程使用,這樣調用 pthread_create的線程就得到了錯誤的線程號。
要避免這種情況可以采取一定的同步措施,最簡單的方法之一是可以在被創建的線程里調用 pthread_cond_timedwait 函數,讓這個線程等待一會兒,留出足夠的時間讓函數 pthread_create 返回。
設置一段等待時間,是在多線程編程里常用的方法。
但是注意不要使用諸如 wait()之類的函數,它們是使整個進程睡眠,并不能解決線程同步的問題。
9.線程使用注意事項
主線程退出其他線程不退出,主線程應調用 pthread_exit避免僵尸線程
pthread_join
pthread_detach
pthread_create 指定分離屬性
被 join 線程可能在 join 函數返回前就釋放完自己的所有內存資源,所以不應當返回被回收線程棧中的值;malloc 和 mmap 申請的內存可以被其他線程釋放應避免在多線程模型中調用 fork 除非,馬上 exec,子進程中只有調用 fork 的線程存在,其他線程在子進程中均 pthread_exit信號的復雜語義很難和多線程共存,應避免在多線程引入信號機制
總結
以上是生活随笔為你收集整理的linux——线程(2)的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。