2012-02-04 88 views
16

我已經在一個類中創建了一個用C創建用戶級線程庫的任務。我想知道是否有人可以給我一個需要閱讀的列表來完成此任務。我對於從哪裏開始有一個好主意,但是用戶級線程中的任何資源以及C語言的某些可能有用的方面都是非常有價值的。實現一個用戶級線程包

我很不清楚我將如何實現這樣的調度。假設我對C語言及其一些更有用的庫函數有很好的理解。

+4

分配是有點難以滿足,因爲它不能這樣做「在C」。您至少需要最少量的程序集或等效的編譯器擴展來方便創建新的執行上下文並在它們之間切換。或者你可以寫自己的完整的虛擬機和C實現在虛擬機上運行,​​但我不認爲這是你的老師有什麼考慮? – 2012-02-04 22:55:39

+1

對於合作多任務/線程,你可能會發現的getContext/makecontext/setcontext函數很有用。 – MetallicPriest 2012-02-04 22:57:41

+0

我看不出這可能沒有一些彙編完成執行保存/恢復寄存器上下文和堆棧指針。這甚至沒有考慮I/O以及如何等待它。 – 2012-02-04 23:01:57

回答

8

我已經完成了這個作業,完全沒有編寫任何彙編程序。線程切換機制是setjmp/longjmp。這涉及到爲每個線程的堆棧分配內存,然後非常小心地按照jmp_buff中的值執行,以便執行跳轉到下一個線程的堆棧。

另請參見拉斯考克斯的漂亮可讀libtask

編輯迴應OP的評論:在決定何時切換線程主要有兩個方向是:搶佔&合作。在搶佔模式,你就會有類似的東西,使執行流程跳轉到一箇中心調度線程,選擇下一個線程來運行一個計時器信號。在合作模型中,線程或者明確地(,例如,通過調用您將提供的yield()函數)或隱式地(,例如,請求由另一線程保持的鎖)「相互」屈服「。

看一看libtask的API爲合作模型,函數taskyield()的特別的描述的一個例子。這是我提到的明確收益率。也有非阻塞I/O功能,其中包括一個隱含的收益率,目前的「任務」被擱置,直到I/O完成,但其他任務讓他們有機會運行。

+0

這是我想象的,我會做線程切換。我想我最大的知識空白是如何確定一個線程何時應該放棄控制,以便另一個可以運行。即線程如何確定他們有足夠的時間。 – SirensOfTitan 2012-02-05 00:28:22

+0

@SirensOfTitan,我已經更新了我的答案來覆蓋你剛剛問。 – 2012-02-05 04:18:04

4

一個簡單的協同調度可以在C使用swapcontext來完成,看在swapcontext手冊頁here的例子,這是它的輸出:

$ ./a.out 
main: swapcontext(&uctx_main, &uctx_func2) 
func2: started 
func2: swapcontext(&uctx_func2, &uctx_func1) 
func1: started 
func1: swapcontext(&uctx_func1, &uctx_func2) 
func2: returning 
func1: returning 
main: exiting 

所以你可以看到它是相當可行的。注意:如果您在定時器信號處理程序中交換上下文,那麼您有自己的先發制人調度程序,但我不確定這是否安全或可能。

編輯:我發現這個在sigaction的,這表明它是可以切換的信號處理器中的上下文的手冊頁:

如果其中sa_flags指定SA_SIGINFO,那麼sa_sigaction(而不是 sa_handler)指定signum的信號處理函數。 該函數接收信號編號作爲其第一個參數,一個 指針指向一個siginfo_t作爲其第二個參數和一個指向 ucontext_t(轉換爲void *)作爲其第三個參數。

+1

考慮到這是一個家庭作業的問題(我已經重新標記它左右), OP應該檢查是否可以接受。更可能的是,教師正在尋找'swapcontext()'功能的實現,而不是簡單地使用它。 – 2012-02-05 04:21:43

1

您可以查看Apple的開源實現。請注意,代碼的最大一部分實際上是彙編代碼,因爲它需要一些你不能在C中完成的特殊事情,比如檢索堆棧幀的返回地址或跳轉到任意地址。

用戶級線程(通常也稱爲「光纖」)通常採用合作模型;也就是說,線程執行直到他們決定他們有足夠的時間,然後屈服於另一個線程。使用優先級隊列,您可以實現一個調度程序來執行已經運行了最短時間的任務。 (調度程序會記錄正在運行的任務,並在運行任務確定足夠時退回運行任務。調度程序會更新任務運行的時間量,然後降低執行時間最短的時間。)