iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 7
2
自我挑戰組

OS作業系統學習系列 第 7

第七天 Thread(執行緒)--下

  • 分享至 

  • xImage
  •  

第七天 Thread(執行緒)--下

今天繼續來講執行緒,這麼多的thread程式設計者能透過執行緒庫所提供的API來管理及創建。而有兩種主要的方式來實做執行緒庫,一種是直接存在user space中,另外一種則是存在kernel space中,由作業系統來支持調配。目前主要使用的多執行緒庫有:Pthreads、Win32 threads跟Java threads,這裡我們只說Pthreads跟Java threads。

Pthreads是由IEEE 1003.1c的標準來定義創建的和操作執行緒的API。他可以提供給user-level或是kernel-level,而且他是一種定義並不是實作。
Java threads是由JVM所管理的,而他用什麼模型來實做,完全是看作業系統給他什麼樣的thread。Java threads的創建有兩種:繼承thread類別或是用Runnable interface產生間接的thread。

那隨著越來越多的thread產生,要能同步會比較困難,那我們就會運用到implicit thread。Implicit thread是由compiler(編譯器)跟run-time libraries來做。那有三種方法來實行:thread pools、OpenMP跟Grand Central Dispatch。
thread pools是一個存放等待被叫去工作的thread的地方,使用率很高。使用它有幾點好處:

  • 省去重新生一個thread都成本
  • 可以有到跟pool一樣大小的threads存在
  • 可以同步處理要求,不用中斷

OpenMP是由compiler來做,提供平行運作在shared-memory的環境中,而且定義平行區域內,哪個code能平行執行。

Grand Central Dispatch是apple的方法,容許識別平行的部分,而且在做thread時,可以不用處理那麼多的事情。Compiler會分割block內的資料到dispatch queue,這樣就可以同步執行。dispatch queue有兩種型態:serial跟concurrent。
Serial就是先送先處理(FIFO原理),像是main queue。Concurrent則是可以同時進行,不用照順序。

那thread還有一些議題我們可以討論:

  1. fork()跟exec() system call語義:
    當thread要被創建時,會運用fork() system call,這時就會看系統是要單一創建被互叫的thread,還是把所有的thread都複製出來。
    用exec() system call的話,就會執行process中所有的thread。

  2. 訊號(signal)的處理:
    Signal對UNIX來說是一個重要的機制,用來通知process抹些事件的發生。會有signal handler來管理這些signal,而signal會生成生是因為被某些特定的事件觸發而產生的。signal handler有兩種處理方式:default或是使用者自己定義。

單一個執行緒時,訊號會直接由process處理,如果是多重執行緒時,毀有以下幾種方式處理:

  • 把訊號傳到應用的thread
  • 把訊號傳給所有的thread
  • 把訊號傳給process中特定thread
  • 選一個thread接收所有的訊號
  1. 執行緒的取消:
    在執行緒完成前,就把它結束掉,而這個被結束掉的thread,我們叫它target thread。提早結束的方式有三種,asynchronous cancellation、deferred cancellation跟actual cancellation。
    asynchronous cancellation是當下說取消就取消; deferred cancellation則是等到他執行到一個週期後才取消掉; actual cancellation會看現在thread是什麼狀態,如果是disabled就要等到enabled時才能取消掉。

  2. 執行緒自己的儲存庫:
    每一個執行緒都准許擁有自己的儲存庫(Thread-Local Storage ,TLS),對thread來說是獨一無二的,不會影響到其他thread的資料。他跟local variable不同的是他可以被自己以外的function看到,就像static一樣。

  3. 排程的啟動:
    LWP (lightweight process),在user thread跟kernel thread中間的資料結構(中介程式),提供虛擬的process做排程,每個LWP都會跟kernel thread做連結。在溝通的機制中,排程的啟動會提供向上呼叫(upcall)的功能,從kernel 到thread library的upcall handler,這個溝通讓程式能維持正確的kernel thread數量。

我們來以作業系統舉例:

在windows中,一個thread有:

  1. ID
  2. 表示處理器狀態的register
  3. User stack、kernel state(在不同地方,用不同stack)
  4. 私有的資料存放庫
    其中2~4皆被稱為context

Thread主要的資料結構有以下幾種:

  1. ETHREAD:包含thread所屬process的指標和指向KTHREAD的指標(不包含thread)
  2. KTHREAD:包含排程跟同步的資料、kernel stack和指向TED的指標(kernel thread)
  3. TED:包含ID、user stack、執行緒自己的儲存庫。(thread 環境)
    ETHREAD和KTHREAD都屬於kernel space,TED則屬於user space。
    https://ithelp.ithome.com.tw/upload/images/20181021/20112132GkgmVBHTdY.png

在Linux中,thread被稱為tasks。Thread的產生是由clone() system call執行,而非fork()。而task生成後,允許跟parent task(process)分享address space。


上一篇
第六天 Thread(執行緒)--上
下一篇
第八天 CPU Scheduling--上
系列文
OS作業系統學習30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言