虛擬地址:
線程:
????????概念:線程是輕量級進程,一般是一個進程中的多個任務。
????????進程是系統中最小的資源分配單位。(競爭計算機資源的最小單位)(進程能分配硬件資源,線程不行)線程是系統中最小的執行單位。
?? ?特征:
?? ?1、共享資源(除了棧區都共享)-->每個進程有獨立的棧區,其他空間其實都用的是所從屬的進程的,有效減少內存開銷
?? ?2、效率高 ?30%
?? ?3、三方庫: pthread ?clone ? posix
?? ??? ??? ?3.1 編寫代碼頭文件: pthread.h
?? ??? ??? ?3.2 編譯代碼加載庫: -lpthread ? library?
?? ??? ??? ?libpthread.so
?? ??? ??? ?gcc 1.c -lpthread?
缺點:
?? ?1,線程和進程相比,穩定性,稍微差些(一個進程崩潰后,在保護模式下不會對其他進程產生影響,但是一個線程崩潰整個進程都死掉。所以多進程要比多線程穩定。)
?? ?2,線程的調試gdb,相對麻煩些。
線程與進程區別:
?? ?變量開銷:進程:3G(物理內存總量),線程:8M(單個程序棧的最大空間)
?? ?資源:
?? ??? ?線程比進程多了共享資源。 ?IPC(進程間通信)
?? ??? ?線程又具有部分私有資源。
?? ??? ?進程間只有私有資源沒有共享資源。
?? ?空間:
?? ??? ?進程空間獨立,不能直接通信。
?? ??? ?線程可以共享空間,可以直接通信。
線程的設計框架?
? ?創建多線程 --> 線程空間操作 --> 線程資源回收
線程創建:pthread_create():
int pthread_create(
?? ??? ?pthread_t *thread, const pthread_attr_t *attr,
?? ??? ?void *(*start_routine) (void *), void *arg);
?? ?功能:該函數可以創建指定的一個線程。
?? ?參數:thread 線程id,需要實現定義并由該函數返回。
?? ??? ? ?attr ? 線程屬性,一般是NULL,表示默認屬性。
?? ??? ? ?start_routine 指向指針函數的函數指針。
?? ??? ? ??? ??? ?本質上是一個函數的名稱即可。稱為
? ? ? ? ? ? ? ? ? 回調函數,是線程的執行空間。
?? ??? ? ?arg ?回調函數的參數,即參數3的指針函數參數。
? ? ? ? ? 如果想要傳多個參數:使用結構體
? ? ? ? ? 返回值:成功 0
?? ??? ?? 失敗 錯誤碼
注:
? ? ? ?一次pthread_create執行只能創建一個線程。
?? ? ?每個進程至少有一個線程稱為主線程。
?? ? ?主線程退出則所有創建的子線程都退出。?
?? ? ?主線程必須有子線程同時運行才算多線程程序。
?? ? ?線程id是線程的唯一標識,是CPU維護的一組數字。
?? ? ?pstree 查看系統中多線程的對應關系。
?? ? ?多個子線程可以執行同一回調函數。
pthread_self():
pthread_t pthread_self(void);
? ?功能:獲取當前線程的線程id
? ?參數:無
? ?返回值:成功 返回當前線程的線程id
? ? ? ? ? ? ? ???失敗 ?-1;?
線程退出:
自行退出-->自殺-->exit()
void pthread_exit(void *retval);? //與return的效果類似
?? ??? ?功能:子線程自行退出
?? ??? ?參數: retval 線程退出時候的返回狀態,臨死遺言。
?? ??? ?返回值:無
強制退出-->他殺-->pthread_cancel()
int pthread_cancel(pthread_t thread);
?? ??? ?功能:請求結束一個線程
?? ??? ?參數:thread 請求結束一個線程tid
?? ??? ?返回值:成功 0
? ? ? ? ? ? ? ? ? ? ? 失敗 -1;
pthread_join()
?int pthread_join(pthread_t thread, void **retval); ? ?
? ? ?功能:阻塞回收。通過該函數可以將指定的線程資源回收,該函數具有
? ?? ? ? ?阻塞等待功能,如果指定的線程沒有結束,則回收線程會阻塞。
? ? ?參數:thread ?要回收的子線程tid
? ? ? ? retval ?要回收的子線程返回值/狀態。-->ptread_exit(值);
? ? ?返回值:成功 0
? ? ? ? ? ? ? ? ? ?失敗 -1;
為什么要用ret要使用二級void指針:
因為ret期望來存儲類似于函數指針,字符串(字符串使用字符數組存儲)的值,這種變量本身就是一級指針,如果我們要在傳參這種操作中能使被調修改主調,必須使用*運算,所以我們傳進去的二級指針
期望的傳參操作:
void* ret;
pthread_create(&tid,NULL,th,NULL);
pthread_join(tid,&ret); //傳入一級指針地址
printf("ret %s\n",(char *)ret); //轉換為需要的類型
printf("ret %d\n",*((char *)ret)); //取兩次*運算
子線程的回收策略:
1、如果預估子線程可以有限范圍內結束則正常用pthread_join等待回收。
2、如果預估子線程可能休眠或者阻塞則等待一定時間后強制回收。
3、如果子線程已知必須長時間運行則,不再回收其資源。
期望傳回的地址:
原理:子線程退出的時候,可以返回一個內存地址
? ? ? 該值所在的內存中可以存儲任何數據,只要
?? ? ?地址存在,則數據都可以正常返回。
?? ?
?? ?地址有三種:
?? ?0、棧區變量 ?錯誤,子線程結束該地址失效。
?? ?1、全局變量 ?失去意義,本質可以直接訪問。
所以可以傳回的地址:
?? ?2、靜態變量?
?? ?3、堆區變量
分離屬性(attribute):
設置分離屬性,目的線程消亡,自動回收空間。
pthread_attr_init
int pthread_attr_init(pthread_attr_t *attr);
?? ?功能,初始化一個attr的變量
?? ?參數:attr,需要變量來接受初始值
?? ?返回:0 ?成功,
?? ?非0 錯誤
?pthread_attr_destroy
int pthread_attr_destroy(pthread_attr_t *attr);
?? ? ?功能:銷毀attr變量。
?? ? ?attr,屬性變量
?? ? ?返回:0 ?成功,
? ? ? 非0 錯誤;
pthread_attr_setdetachstate
功能:把一個線程設置成相應的屬性
?? ?參數,attr,屬性變量,有init函數初始化他。
?? ?detachstate:有2個可選值,
?? ?設置分離屬性:
?? ?PTHREAD_CREATE_DETACHED(分離線程)
?? ?PTHREAD _CREATE_JOINABLE(非分離線程)
第二種設置分離屬性的函數:pthread_deatch
int pthread_deatch(pthread_t thread);
?? ?功能,設置分離屬性
?? ?參數,線程id號,填自己的id? ? ? ??
清理函數:
pthread_cleanup_push()
void pthread_cleanup_push(void (*routine)(void *), void *arg);
?? ?功能:注冊一個線程清理函數
?? ?參數,routine,線程清理函數的入口
?? ??? ?arg,清理函數的參數。
?? ?返回值,無
需要滿足以下條件才會調用注冊的回調函數:
1.線程被取消的時候(pthread_cancel)
2.線程主動退出的時候(pthread_exit)
3.pthread_cleanup_pop的參數為非0值(pthread_cleanup_pop)
pthread_cleanup_pop:
void pthread_cleanup_pop(int execute);
?? ?功能:調用清理函數
?? ?execute,非0 ?執行清理函數
?? ??? ?0 ,不執行清理
?? ??? ??? ?
?? ?返回值,無