2013-02-09 45 views
1

所以我現在正在學習線程,我想知道如何處理一些事情。例如,假設我有一個程序,其中一個線程偵聽輸入,另一個線程在單個處理器上執行一些計算。當計算線程正在運行時,如果用戶應該按下用於輸入線程的按鈕,會發生什麼情況?在輸入線程切換到特定線程之前,輸入是否會被忽略?線程:當線程正在運行時,您可以與其他線程交互嗎?

回答

3

它很大程度上取決於輸入機制是如何實現的。實現I/O的一種簡單但非常無法實現的方式是連續輪詢 ...在這種情況下,輸入線程可能會坐在一個循環中,一遍又一遍地讀取硬件寄存器,並且當寄存器從0到1變化時,輸入線程將知道,按下該按鈕:

void inputThread() 
{ 
    while(1) 
    { 
     if (some_register_indicates_the_button_is_pressed()) react(); 
    } 
} 

這種方法的問題是它的效率極其低下 - 輸入線程使用數十億的CPU週期的只是檢查寄存器一遍又一遍地。在運行此代碼的多線程系統中,線程調度程序會在繁忙等待輸入線程和計算線程之間切換每個量程(例如,每10毫秒一次),以便輸入線程使用一半CPU週期和計算線程會使用另一半。在這個系統中,如果輸入線程在用戶按下按鈕的瞬間運行,那麼輸入將幾乎是瞬間檢測到,但是如果計算線程正在運行,那麼直到下一次輸入線程得到時纔會檢測到輸入運行,所以可能會有10毫秒的延遲。 (更糟糕的是,如果用戶過早釋放按鈕,輸入線程可能永遠不會注意到它被按下)

對連續輪詢的改進是定時輪詢。它的工作原理與上面相同,不同之處在於代替輸入線程在一個循環中只輪詢,它會輪詢一次,然後睡了一小會兒,然後再調查:

void inputThread() 
{ 
    while(1) 
    { 
     if (some_register_indicates_the_button_is_pressed()) react(); 
     usleep(3000); // sleep for 30 milliseconds 
    } 
} 

這是第一個效率低下的要少得多因爲每次調用usleep()時,線程調度程序都會使輸入線程進入休眠狀態,並使CPU立即可供其他線程使用。 usleep()還會設置一個硬件定時器,當該硬件定時器關閉(30毫秒後)時,會引發中斷。中斷會導致CPU不管它在做什麼,並再次運行線程調度代碼,並且線程調度代碼將(在大多數情況下)意識到它返回usleep()的時間,並喚醒輸入線程所以它可以做循環的另一個迭代。這仍然不完美:inputThread仍在持續使用少量的CPU - 並不是很多,但是如果你做了很多這樣的實例,它開始累積起來。此外,按鈕一直處於睡眠狀態的問題仍然存在,甚至更可能。

這導致我們到中斷驅動的I/O。在這個模型中,輸入線程根本不輪詢;相反,它告訴操作系統通知它,當按下按鈕:

void inputThread() 
{ 
    while(1) 
    { 
     sleep_until_button_is_pressed(); 
     react(); 
    } 
} 

操作系統的通知工具,反過來,有這麼當按下按鈕時OS通知,這樣就設置好了的OS可以喚醒並通知輸入線程。操作系統通過告訴按鈕的控制硬件在按下按鈕時產生中斷來實現這一點;一旦該中斷關閉,其工作原理與上例中的定時器中斷非常相似。 CPU運行線程調度器代碼,該代碼看到是時候喚醒輸入線程,並讓輸入線程運行。這種機制具有非常好的屬性:(1)當按鈕被按下時,輸入線程被ASAP喚醒(沒有等待計算線程首先完成它的量子),以及(2)輸入線程沒有吃掉任何CPU週期,除了按下按鈕時。由於這些優點,正是這種機制在現代計算機中用於任何不平凡的I/O。

請注意,在現代的PC或Mac上,不僅僅是兩個線程和一個硬件按鈕,例如有幾十個硬件設備(鍵盤,鼠標,顯卡,硬盤,網卡,聲卡等)以及數十個同時運行的程序,操作系統的工作就是根據需要進行調解。儘管如此,總體原則仍然是一樣的;比方說,在你的例子中,用戶點擊的按鈕不是物理按鈕,而是屏幕上的GUI按鈕。在這種情況下,會發生類似的事件順序如下:

  1. 用戶的手指按下鼠標左鍵
  2. 鼠標的內部硬件通過USB電纜發送一個鼠標按鈕按下消息到計算機的USB控制器
  3. 電腦的USB控制器產生一箇中斷
  4. 中斷導致CPU打出來的計算線程的代碼並運行該操作系統的調度程序
  5. 線程調度器看到的是,USB中斷線指示USB活動已準備就緒,並通過運行USB驅動程序的中斷處理程序代碼來響應USB驅動程序的中斷處理程序代碼讀取事件,發現它是一個鼠標按鈕按下的事件,並將其傳遞給窗口管理器。
  6. 窗口管理器知道哪個窗口具有焦點,所以它知道哪些程序的鼠標按鈕按下事件轉發到
  7. 窗口管理器告訴OS喚醒與該窗口
  8. 你輸入線程醒來,並呼籲作出反應(相關聯的輸入線)
1

如果你在一個處理器系統上運行,那麼是的。

+1

..但是一旦輸入發生就會發生這種情況(大多數O S,無論如何)。 – 2013-02-09 19:40:03

1

那麼,線程可以通過多種方式相互交流。其中之一是具有全局變量並將其用作通信線程線程的緩衝區。
當您詢問有關按鈕時,必須有一個包含事件加載器循環的線程。根據我的經驗,在這個線程中,輸入不會被忽略。

你可以看到我的一些關於這個主題的線索:
Here,我很感興趣如何使3線程應用程序通過事件進行通信。

1

簡短回答:是的,線程總是互動。當他們以不可預測的方式進行交互時,問題就開始出現。進程中的每個線程都可以訪問整個進程內存空間,因此在一個線程中更改內存可能會損壞另一個線程的數據。

1

等待用戶輸入的線程將立即「就緒」。在大多數操作系統上,正在等待I/O並準備就緒的線程會得到臨時優先級提升,即使在單核CPU上,也會立即搶佔以相同優先級運行的另一個線程。因此,如果一個單核CPU正在運行計算,而另一個正在等待的同一優先級的線程被輸入,它可能會立即運行。