SylixOS中pthread_cancel淺析

1.知識簡介

1.1 概述

       取消一個線程要確保該線程可以釋放其所持有的任何鎖、分配的內存,使整個系統保持一致性。在不少狀況下要保證這種正確性是有必定困難的。安全

       一種簡單的線程取消:取消線程調用一個取消線程的函數,被取消線程死亡。在這種狀況下,被取消線程所持有的的資源得不到釋放。取消線程負責保證被取消者處於可安全取消狀態,在一個要求可靠性高的系統中,這種保證很是困難或者沒法實現。這種取消稱爲不受限制的異步取消異步

       還存在另一種更安全的線程取消機制。一個線程能夠以可靠的受控制的方式向進程的其餘線程發出取消請求,目標線程能夠掛起這一請求使實際的取消動做在此後安全的時候進行,稱爲延遲取消。目標線程還能夠定義其被取消後自動被系統調用的線程清除函數。函數

       SylixOS兼容絕大多數POSIX接口, SylixOS中pthread_cancel函數執行線程取消功能。spa

       pthread_cancel 函數和目標線程的取消動做是異步的。根據目標線程的取消屬性不一樣,取消請求可能被忽略、當即執行或者延遲處理。爲了清楚這些動做,下面知識點先簡單介紹線程取消屬性相關概念。線程

1.2 知識點

       SylixOS中pthread_cancel函數由px_othread.h頭文件定義,其原型爲:接口

        int  pthread_cancel (pthread_tthread);進程

  •       此函數成功返回 0,失敗返回錯誤號;
  •       參數 thread 是取消的線程句柄。

 

      SylixOS中用取消狀態,取消類型和取消請求這3個元素共同表示一個線程的取消屬性,其存在於線程控制塊中。如表2‑1所示。內存

表2‑1  取消說明資源

       線程初始化時會有默認的取消屬性,即線程保留容許取消延遲取消的屬性,保證收到取消信號時,線程接受該取消信號,不會屏蔽掉,而且會在自身安全的時候,調用線 程刪除函數,即延遲取消。另一個線程的取消狀態和取消類型可分別調用相關函數設置,如表 2‑2所示。函數均在px_pthread.h頭文件中定義。開發

表2‑2  設置取消屬性

       前文提到,延遲請求會使線程的取消動做在安全的時候進行,那線程具體的取消時機是在何時呢?會涉及到「取消點」的概念,在後續章節中介紹。

2.技術實現

2.1 實現流程

       SylixOS中pthread_cance函數實現機制,如圖3‑1所示。

圖3‑1  pthread_cancel函數實現流程

2.2 取消點概念

       在使用延遲取消機制時,一個線程在能夠被取消的地方定義取消點,當收到取消請求時,被取消的線程執行到取消點時退出,或者在一個取消點調用被阻塞時退出。

       因爲在延遲取消中必須在取消點才能被取消,這一限制可能使取消請求被掛起任意長時間。所以,若是某個調用可能使線程被阻塞或者進入某個較長時間的過程, POSIX 要求這些調用屬於一個取消點,或者稱這些調用爲取消點調用,以防止取消請求陷入長時間等待,SylixOS中存在一些擁有取消點的函數,如open,read,pthread_join,printf等,他們都直接或間接的調用了pthread_testcancel函數, pthread_testcancel函數內部實現流程如圖 3‑2所示。

圖3‑2  pthread_testcancel函數實現流程

       所以,被取消線程會在執行擁有取消點的函數時,進入到pthread_testcancel函數內部,進行如圖 3‑2所示的容許取消、延遲取消以及取消請求標誌的判斷流程,假若條件知足,被取消線程會在這裏調用線程刪除函數刪除自身。

       表 3‑1列出部分擁有取消點的函數以供參考。

表3‑1  擁有取消點的函數

3 示例演示

       如下示例驗證均在SylixOS環境下進行。

3.1 示例1:當即取消

       如圖 4‑1所示,子線程設置當即取消類型,那麼主線程成功發送取消信號後,打印「pthread_cancel OK」,子線程會在下次執行開始處刪除自身,退出時子線程i的值可能爲0~1000000任意值。

圖4‑1  當即取消示例

3.2 示例2:延遲取消

       如圖 4‑2所示,子線程設置延遲取消類型,那麼主線程執行取消線程函數後,打印「pthread_cancel OK」,子線程會在執行到取消點時刪除自身,sleep爲擁有取消點的函數,所以子線程退出時i 的值必定爲1000000。(即pthread_cancel函數成功返回並不能表明目標線程已經退出)

圖 4‑2  延遲取消示例

       假若示例1和示例2都把子線程中入口函數中的sleep(1)這條語句去掉,那麼示例1中的當即取消仍然有效;示例2中的延遲取消雖然主線程打印「pthread_cancel OK」,可是由於子線程的while(1)循環裏沒有「取消點」,子線程的取消請求一直都不能被處理,所以子線程並不會被成功取消,而是繼續循環運行。如圖 4‑3所示。

圖4‑3  沒有「取消點」

       不過咱們能夠手動加入pthread_testcancel函數進行取消請求處理,這樣子線程也就有了一個「取消點」,在「取消點」取消請求被處理,線程便可退出。如圖 4‑4所示。

圖4‑4  pthread_testcancel處理取消請求

4. 總結

       當即取消會經過信號方式修改目標線程任務上下文環境,即把舊目標線程任務上下文作適當偏移,將信號處理句柄安裝在上下文開始處,組成新的目標線程任務上下文,當任務調度輪到目標線程執行時,目標線程會優先執行信號處理程序,完成信號請求的動做。這裏要注意時任務調度以後當即取消,由於任務調度切換任務上下文會花費一些時間,因此當即取消並不表明時間上的「馬上」。

       延遲取消僅僅使目標線程的線程控制塊相關標誌修改,在目標線程執行到相關擁有取消點的函數時,進行取消請求檢查,知足條件纔會刪除線程。即任務調度以後,目標線程還會繼續執行任務上下文指定任務,直到碰到「取消點」,纔可能取消線程。

       pthread_cancel的成功返回僅僅代表調用該函數的線程完成了對目標線程線程控制塊相關標誌的修改,等到任務調度,目標線程纔會檢查這些標誌,作出相應處理,即pthread_cancel的成功返回並不能表明目標線程的徹底取消。

       因而可知,線程取消並非安全的,當即取消會讓目標線程「當即退出」,延遲取消會給目標線程從開始到「取消點」爭取一段執行時間,若是沒有「取消點」,目標線程就不能完成預期的線程取消動做,這些都有可能形成不少不安全的因素,目標線程取消以前佔有的資源如互斥鎖,互斥鎖沒有釋放線程就退出了,將致使別的線程沒法得到改鎖從而一直阻塞,更嚴重的還會形成死鎖現象。

       線程能夠安排它退出時調用線程清理處理程序,經過pthread_cleanup_pop和pthread_cleanup_push函數能夠將有些「後事」在線程退出後交給線程清理處理程序幫忙處理,本文檔這次主要淺析SylixOS的pthread_cancel流程,就不對線程清理處理程序如何使用作詳細介紹了。

5. 參考資料

       SylixOS內核源碼

     《SylixOS應用程序開發手冊》

相關文章
相關標籤/搜索