線程的創建&屬性

注:筆者這些文檔多出自APUE這本書,旨在督促自己堅持學習,其中沒有給出實際的編碼例子,是因爲本身快速學習的原則,即“花20%的時間掌握80%的內容”,具體的實戰會在後續網絡編程中一一體現。個人覺得學習編程最佳的路徑是在解決問題中掌握知識點。因此線程這幾篇都只會講述個人理解的基礎概念。

線程創建的相關函數:

1.  int pthread_create(pthread_t*thread, const pthread_attr_t *attr, void*(*start_routine) (void *),  void *arg);  

返回值:若成功,返回0;否則返回錯誤編號

Eg.

pthread_t  thread_id;

pthread_create(thread_id, &attr,&thread_start, &tinfo[tnum]);

  • thread_id---------線程創建成功後用於存放線程ID的位置
  • attr--------------線程的屬性,若設置爲NULL則表示默認
  • thread_start------新創建的線程從thread_start函數的地址開始運行
  • tinfo[tnum]-------需要向thread_start函數傳遞的參數
2.  int pthread_equal(pthread_t t1, pthread_t t2);

返回值:對比t1和t2兩個線程是否相等,若相等返回非0數值;否則,返回0

  •  線程ID只有在它所屬的進程上下文中才有意義,這點和進程ID是有區別的。
3.  pthread_t pthread_self(void);---獲取線程自身的線程ID

返回值:調用線程的線程ID

線程終止:

線程的終止分爲兩大類:主動終止,被動終止

主動終止

  •  線程函數執行return正常返回,返回值就是線程的退出碼;
  •  線程調用pthread_exit函數,其參數就是線程的退出碼;

被動終止

  • 在其他線程中調用pthread_cancel函數;
  • 任意線程調用exit家族的函數,這種方式比較極端,會導致整個進程退出;

1.  void pthread_exit(void*retval);

Eg.

pthread_exit((void *)2);

  • retval-----------線程的返回值,即終止狀態
2.  int pthread_cancel(pthread_t thread);

返回值:若成功,返回0,;否則,返回錯誤編號

  • 線程通過調用這個函數來請求(並不等待線程終止,它僅僅是提出請求)取消同一進程中的其他線程。

             它的行爲等同於pthread_exit(PTHREAD_CANCELED);

3.  int pthread_join(pthread_tthread, void **retval);

返回值:若成功,返回0;否則,返回錯誤編號

調用線程將一直阻塞,直到指定的線程調用pthread_exit,從啓動例程中返回或者被取消。

retval------如果線程從啓動例程中返回,則retval就包含返回碼

retval------如果線程被取消,就由retval指定的單元被設置爲PTHREAD_CANCELED

  • 在調用pthread_join的時候還需要直到線程的啓動狀態,如果線程是分離狀態啓動的那麼,pthread_join調用就會失敗,返回EINVAL,如果是以非分離狀態啓動的pthread_join就會把線程置於分離狀態,這樣就可以回收線程資源。
4.    如果線程被設置爲分離狀態,那麼線程的底層存儲資源可以在線程終止時立即被回收,那麼我們怎麼將線程設置爲分離狀態呢?

int pthread_detach(pthread_tthread);

返回值:若成功,返回0;否則,返回錯誤編號。


線程清理處理程序:

線程可以安排它退出時需要調用的函數,這與進程在退出時可以使用atexit函數註冊退出函數類似。

一個線程可以建立多個清理處理程序。處理程序記錄在棧中,也就是說,他們執行順序與他們註冊時相反。

1.   void pthread_cleanup_push(void (*rtn)(void *), void *arg);

rtn------清理函數rtn是由pthread_cleanup_push函數調度的,調用時只有一個參數arg;

2.  voidpthread_cleanup_pop(intexecute);

execute------參數設置爲0時,清理函數不被調用。

無論如何pthread_cleanup_pop都將會刪除上次pthread_cleanup_push調用建立的清理處理程序。

注意:pthread_cleanup_push和pthread_cleanup_pop必須成對使用。這個可以做個試驗測試一下,註釋掉你的pthread_cleanup_pop編譯會產生什麼結果。

線程和進程之間的相似之處:

進程原語

線程原語

描述

fork                            

pthread_create                        

創建新的控制流

exit

pthread_exit

從現有的控制流中退出

waitpid

pthread_join

從控制流中得到退出狀態     

atexit

pthread_cleanup_push

註冊退出清理函數

getpid

pthread_self

獲取控制流ID

abort

pthread_cancel

請求控制流的非正常退出


線程屬性:

在前面創建線程的時候我們調用pthread_create函數中有個參數,

const pthread_attr_t *attr是關於設置線程屬性的。

接下來就詳細總結一下Linux線程的屬性。

pthread_attr_t 這個結構體表示將爲創建的線程指定類型,該類型的結構體包含了如下屬性:

1. detachstate:線程的分離屬性          

它表示線程結束的時候,是否回收資源。

  • PTHREAD_CREATE_JOINABLE:這種是默認屬性,表示在線程結束時不回收資源,需要調用pthread_join函數來回收;
  • PTHREAD_CREATE_DETACHED:表示線程結束,直接釋放資源;

用於設置和獲取detach state的函數如下:

int pthread_attr_setdetachstate(pthread_attr_t *attr,int *detachstate);

int pthread_attr_getdetachstate(const pthread_attr_t*restrict attr, int *detachstet );

2.  scope:線程的競爭域

該屬性有兩種:

  • PTHREAD_SCOPE_SYSTEM:表示線程和整個操作系統中的線程進行競爭;
  • PTHREAD_SCOPE_PROCESS:表示線程只和當前進程內的線程進行競爭,比如線程調度的時候只考慮當前進程中的線程;

用來設置和獲取scope的函數如下:

int pthread_attr_setscope(pthread_attr_t *attr, int scope);

int pthread_attr_getscope(const  pthread_attr_t*attr, int *scope);

3.  inheritscheduler:調度繼承性

該屬性有兩種:

  • PTHREAD_INHERIT_SCHED:繼承進程的調度策略
  • PHTREAD_EXPLICIT_SCHED:不使用繼承的調度策略,而是使用自己提供的調度策略。

用來設置和獲取inherit scheduler的函數如下:

int pthread_attr_setinheritsched(pthread_attr_t *attr, int inheritsched);

int pthread_attr_ getinheritsched(const  pthread_attr_t*attr, int *inheritsched);

4.  schedulingpolicy:調度策略

分兩大類:

  • 普通調度策略(非實時的調度策略):主要包括SCHED_OTHER、SCHED_BATCH和SCHED_IDLE
  • 實時調度策略:主要包括SCHED_FIFO和SCHED_RR

用於設置和獲取policy的函數如下:

int pthread_attr_setschedpoilcy (pthread_attr_t *attr, int poilcy);

int pthread_attr_ getschedpoilcy(const  pthread_attr_t*attr, int *poilcy);

5.  schedulingpriority:線程優先級

使用如下函數來設置和獲取:

pthread_attr_setschedparm(pthread_attr_t *attr,const structsched_param *param);

pthread_attr_getschedparm(pthread_attr_t *attr, struct sched_param *param);

6.  guardsize:警界緩衝區大小,默認值是PAGE_SIZE(4096KB)

用來設置和獲取線程棧末尾的警戒緩衝區大小,如果線程棧運行到了警戒區,就會收到信號。

使用如下函數來設置和獲取:

int pthread_attr_getguardsize(constpthread_attr_t *attr, size_t *guardsize);

int pthread_attr_setguardsize(pthread_attr_t*attr, size_t guardsize);

7.  stackaddress:棧起始地址(棧最低內存地址)

一般來說在X86或者X64處理器上,棧都是往地地址方向的,所以該值一般表示棧的末尾(棧頂)

使用如下兩個函數來對其進行設置和獲取:

int pthread_attr_getstack(constpthread_attr_t *attr, void **stackaddr,         size_t *stacksize);

int pthread_attr_setstack(pthread_attr_t*attr, void *stackaddr, size_t stacksize);

8.  stacksize:棧大小

對於棧的大小,可以使用如下函數進行設置和獲取:

intpthread_attr_getstacksize(constpthread_attr_t *attr, size_t*stacksize);

intpthread_attr_setstacksize(pthread_attr_t*attr,   size_tstacksize);

以上屬性目前我最常用的就是detach state(線程的分離屬性)。

















發佈了25 篇原創文章 · 獲贊 6 · 訪問量 5950
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章