linux-執行緒
linux-執行緒
- 執行緒的概念
1>linux的執行緒與windos的執行緒區別很大(win的執行緒比較完善,程式不行,linux的程式發展的更早)
2>每一個程式都會分配0-4G的虛擬空間地址,而執行緒共享0-4G的虛擬地址空間,但每一個執行緒有自己不同的pcb.但pcb中指向記憶體資源的三級頁表是相同的
三級頁表(mmu對映虛擬地址到實體記憶體的過程)
3>執行緒是最小的執行單位(搶佔cpu的最小單位(根據執行緒的LWP號(使用ps -Lf pid//檢視指定的執行緒LWP號))),程式是最小的資源分配單位(0-4G資源分配).
4>程式可以蛻變成執行緒
5>執行緒可看做是暫存器和棧的集合
- 執行緒之間共享的資源和非共享的資源
1>執行緒共享的資源
a:檔案描述符表
b:每種訊號的處理方式(所以執行緒不建議使用訊號,共享處理,互相干擾)
c:當前工作目錄(因為建立執行緒需要程式,程式不變,多個執行緒自然共享工作目錄)
d:使用者ID和使用者組ID
e:記憶體地址空間(.text/.data/.bss/heap/共享庫)(除開了棧空間:因為棧空間儲存的每個執行緒的函式h和變數)
2>執行緒獨享的資源
a:執行緒ID
b:處理器現場和棧指標(核心棧)
c:獨立的棧空間(使用者空間棧)
d:errno變數
e:訊號遮蔽字(系統阻塞訊號集)
f:排程優先順序
- 執行緒與程式的對比
優點:1>程式的併發性更高(搶佔cpu的執行時間更強);2>開銷小(與程式相差不是特別大);3>資料通訊,共享資料方便;(因為工共享使用者區(出去棧空間))
缺點(都不是很突出的問題):1>執行緒多使用庫函式,相比系統函式不穩定;2>不支援gdb除錯;3>對訊號支援不友好;
- 執行緒控制函式
1>pthread_self()函式:相當於getpid();獲取當前執行緒的ID號(用於程式間識別不同的執行緒).(注意:不應使用pthread_create()函式的傳出引數獲取執行緒的ID號,而應使用該函式)
2>pthread_create()函式(相當於fork()函式)
注意:linux環境下,所有執行緒特點,失敗若有返回值,直接返回的是編號;(區別程式)
3>pthread_exit()函式(注意:exit();pthread_exit();return ;三者線上程程式設計中的使用)
a:pthread_exit:結束呼叫該函式的執行緒;
b:return:返回到呼叫函式的地方(上一級)
c:exit:結束程式,所有的執行緒也會結束(執行緒程式設計慎重使用)
4>pthread_join()函式(相當於wait()函式(阻塞等待回收))
注意:程式是父程式給子程式回收,但是執行緒可以不,子執行緒也可以呼叫該函式進行回收指定的執行緒.
5>pthread_detach()函式(執行緒獨有的)
將執行緒分離,分離後的執行緒結束後自動清理pcb控制部分的資源回收;常用於伺服器裡.分離後的執行緒就不需要pthread_join()函式回收(回收分離執行緒會報錯);
6>pthread_cancel()函式
注意:殺死(取消)執行緒,相當於程式的kill()函式,但是pthread_cancel()函式不是實時的,必須到達取消點(比如系統呼叫:pause,wait,等函式,man 7 pthreads檢視取消點)才會取消.
#include<stdio.h>
#include <pthread.h>
#include<unistd.h>
#include<stdlib.h>
#include <string.h>
/*******************************************************
*函式:pthread_self()
*標頭檔案: #include <pthread.h>
*格式: pthread_t pthread_self(void); //pthread_t:typedef unsigned long int型別
*注意: Compile and link with -pthread(編譯和連結時加上-pthread引數)
*作用:獲取當前程式的ID號
*返回值:returning the calling thread's ID.
********************************************************/
/*******************************************************
*函式:pthread_create()
*標頭檔案: #include <pthread.h>
*格式:int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
*引數:pthread_t *thread:傳出引數;儲存系統分配的執行緒號;
*const pthread_attr_t *attr:通常傳入NULL,表示使用執行緒的預設屬性.(可以通過此引數將建立的執行緒設定為遊離狀態(分離),執行緒棧空間大小的修改(容納更多的執行緒))
*void *(*start_routine) (void *):函式指標(函式返回值為 void *,引數為 void *型別的),指向表示執行緒體的函式,該函式執行完,
*新建立的執行緒就結束.void *arg:執行緒主體函式的引數;
*注意: Compile and link with -pthread(編譯和連結時加上-pthread引數)
*作用:建立一個新的執行緒,主執行緒繼續向下執行,而子執行緒去執行start_routine函式的動作
*返回值:On success, pthread_create() returns 0; on error, it returns an error number, and the contents of *thread are undefined.
********************************************************/
/*******************************************************
*函式:pthread_detach()
*標頭檔案: #include <pthread.h>
*格式:int pthread_detach(pthread_t thread);//pthread_t thread: pthread_create()第一個引數返回的執行緒號
*注意: Compile and link with -pthread(編譯和連結時加上-pthread引數)
*作用:分離執行緒,執行緒結束後自動回收核心資源,不需要再次呼叫pthread_join()進行回收.
*返回值:On success, pthread_detach() returns 0; on error, it returns an error number.
********************************************************/
/*******************************************************
*函式:pthread_join()
*標頭檔案: #include <pthread.h>
*格式:int pthread_join(pthread_t thread, void **retval);//pthread_t thread:pthread_create()函式建立執行緒時第一個引數傳出的ID值;
*void **retval:接受執行緒的返回值.(注意型別轉換)
*注意: Compile and link with -pthread(編譯和連結時加上-pthread引數)
*作用:阻塞回收指定子執行緒(相當於程式中的wait()函式)(在回收的時候可以傳遞引數出來)
*返回值:On success, pthread_join() returns 0; on error, it returns an error number.
********************************************************/
/*******************************************************
*函式:pthread_exit()
*標頭檔案: #include <pthread.h>
*格式: void pthread_exit(void *retval);//void *retval:範型引數,無返回值
*注意: Compile and link with -pthread(編譯和連結時加上-pthread引數)
*作用:terminate calling thread(將呼叫該函式的執行緒結束)
*返回值:無
*區別: return:返回到呼叫函式的地方
* pthread_exit():將呼叫該函式的執行緒結束
* exit():結束程式,所有的執行緒也會結束(執行緒程式設計慎用)
********************************************************/
/*******************************************************
*函式:pthread_cancel()
*標頭檔案: #include <pthread.h>
*格式:int pthread_cancel(pthread_t thread);//pthread_t thread:pthread_create()函式建立執行緒時第一個引數傳出的ID值;
*注意: Compile and link with -pthread(編譯和連結時加上-pthread引數)
*作用:殺死執行緒(相當於程式中的kill()函式)
*返回值:On success, pthread_cancel() returns 0; on error, it returns a nonzero error number.
********************************************************/
int var=100;//區分執行緒,子執行緒進行更改,全域性也會更改,證明執行緒的全域性變數是共享的(程式是:讀時共享,寫時複製)
int i=1;
int k=1;
//用於pthread_join()函式回收使用
typedef struct exit_c{
int sta;
char c;
int num;
}exit_t;
//子線主體函式
void * pthread_func( void *arg)
{
exit_t *retval=(exit_t*)arg;//再一次格式轉換
sleep(retval->num);
var=1000;
retval->c='M';
retval->sta=retval->num+1;
printf("%dth thread ID is:%lu,process ID id %d,var=%d\n",retval->num+1,pthread_self(),getpid(),var);
pthread_exit((void *)retval);//這裡等同return 0;但是使用exit(0)會導致程式退出,所有執行緒也會退出.//注意(void *)retval型別轉換;
}
/*******************************************************
*驗證執行緒控制原語
*******************************************************/
int main()
{
pthread_t tid[5]; //存放五個執行緒的tid
int ret,ret1;
exit_t *retval[5];
//迴圈建立5個執行緒,區別程式(執行緒不用考慮子執行緒建立子執行緒的問題,如果要子執行緒建立子執行緒,需要在pthread_func()函式再次呼叫pthread_create()函式.)
for(int i=0;i<5;i++)
{
retval[i]=(exit_t*)malloc(sizeof(exit_t));
retval[i]->num=i;
ret=pthread_create(&tid[i],NULL,pthread_func,(void *)retval[i]);//注意:(void *)retval:retval是需要轉換型別的,進行的是傳值操作;如果這裡傳入retval,進行傳地址操作;
//會導致錯誤(5個執行緒的產生很快完成,但是執行緒的主體函式不一定執行完,所以就會導致上一個執行緒與下一個執行緒的值相等,所以在傳地址的時候保證地址的唯一性;(建立一個執行緒就均可傳值\傳地址)
//ret1=pthread_detach(tid[i]);//如果此處設定執行緒分離,後面就不用呼叫pthread_join()函式進行執行緒回收
if(ret!=0)
{
fprintf(stderr,"pthread_create error:%s\n",strerror(ret)); //char *strerror(int errnum);//該函式只需傳入錯誤號,然後就會輸出對應的錯誤描述(程式程式設計就會直接返回錯誤描述);int fprintf(FILE *stream, const char *format, ...);
exit(1);
}
}
sleep(i);//保證每個執行緒都去執行執行緒主體函式
//回收5個執行緒
sleep(6);//保證子執行緒建立完畢
for(int i=0;i<5;i++)
{
pthread_join(tid[i],(void **)&retval[i]);//阻塞等待回收子執行緒;//(void **)&retval[i]一級指標轉為二級指標:先取地址,再轉為二級指標
printf("**************************************************\n");
printf("%dth thread was Recycled: sta:%d; c:%c; \n", retval[i]->num+1 ,retval[i]->sta,retval[i]->c);
free(retval[i]);
}
printf("*******in mian thread ID is:%lu,process ID id %d,var=%d*********\n",pthread_self(),getpid(),var);
pthread_exit(NULL);//主控執行緒結束,並不會導致程式ID號的改變// 這裡如果不加slepp(); return 0;和exit(0);都會是程式退出;
}
執行結果:
- 執行緒\程式控制函式對比
注意:分離執行緒回收會報錯22(所以分離的執行緒不用回收),殺死的執行緒回收值為-1;(pthread_testcancel()函式是加入取消點的作用)
- 執行緒使用的注意事項
1>注意NPTL庫版本一致(使用命令檢視:getconf GNU_LIBPTHREAD_VERSION)(GNU提供執行緒庫,程式設計平臺不一樣時需要保證該庫的版本一致)
2>編譯的時候加上 -pthread (引入執行緒庫)
3>主執行緒退出,其他執行緒不退出時應該呼叫pthread_exit(),如果用其他的(return exit)導致程式退出,全部執行緒也會退出
4>避免殭屍執行緒:1:pthread_join()回收執行緒;2:pthread_detach()函式分離執行緒;3:pthread_creat()函式第二個引數指定建立的執行緒為遊離態;
5>各個執行緒共享堆區,所以malloc()和mmap分配的空間可以區其他執行緒釋放;
6>避免線上程裡使用fork()函式
7>避免線上程裡引入訊號機制;
相關文章
- linux-多執行緒Linux執行緒
- 多執行緒------執行緒與程式/執行緒排程/建立執行緒執行緒
- 多執行緒-執行緒控制之休眠執行緒執行緒
- 多執行緒-執行緒控制之加入執行緒執行緒
- 多執行緒-執行緒控制之禮讓執行緒執行緒
- 多執行緒-執行緒控制之中斷執行緒執行緒
- 多執行緒-執行緒控制之守護執行緒執行緒
- 執行緒和執行緒池執行緒
- 多執行緒【執行緒池】執行緒
- 多執行緒--執行緒管理執行緒
- Java多執行緒——執行緒Java執行緒
- 執行緒 執行緒池 Task執行緒
- 執行緒與多執行緒執行緒
- 保證執行緒在主執行緒執行執行緒
- 多執行緒之初識執行緒執行緒
- Java多執行緒-執行緒中止Java執行緒
- 執行緒控制之休眠執行緒執行緒
- Java多執行緒——執行緒池Java執行緒
- c#執行緒-執行緒同步C#執行緒
- 多執行緒-執行緒概述等執行緒
- 執行緒1-單執行緒執行緒
- 執行緒3--執行緒安全執行緒
- 執行緒同步及執行緒鎖執行緒
- Java執行緒:執行緒中斷Java執行緒
- 【多執行緒總結(二)-執行緒安全與執行緒同步】執行緒
- 執行緒、開啟執行緒的兩種方式、執行緒下的Join方法、守護執行緒執行緒
- java執行緒之守護執行緒和使用者執行緒Java執行緒
- 執行緒(一)——執行緒,執行緒池,Task概念+程式碼實踐執行緒
- java 多執行緒守護執行緒Java執行緒
- Java多執行緒-執行緒通訊Java執行緒
- Java多執行緒-執行緒狀態Java執行緒
- Java多執行緒(2)執行緒鎖Java執行緒
- java多執行緒9:執行緒池Java執行緒
- 二. 執行緒管理之執行緒池執行緒
- Java多執行緒之執行緒中止Java執行緒
- 多執行緒系列之 執行緒安全執行緒
- iOS 多執行緒之執行緒安全iOS執行緒
- 【java多執行緒】(二)執行緒停止Java執行緒