您的位置 首页 kreess

11.1 線程(Thread)概述

我們今天的課程會討論線程以及XV6如何實現線程切換。今天這節課與之前介紹的系統調用,Interrupt,page table和鎖的課程一樣,都是有關XV6底層實現的課程。今

我們今天的課程會討論線程以及XV6如何實現線程切換。今天這節課與之前介紹的系統調用,Interrupt,page table和鎖的課程一樣,都是有關XV6底層實現的課程。今天我們將討論XV6如何在多個線程之間完成切換。

為什麼計算機需要運行多線程?可以歸結為以下原因:

  • 首先,人們希望他們的計算機在同一時間不是隻執行一個任務。有可能計算機需要執行分時復用的任務,例如MIT的公共計算機系統Athena允許多個用戶同時登陸一臺計算機,並運行各自的進程。甚至在一個單用戶的計算機或者在你的iphone上,你會運行多個進程,並期望計算機完成所有的任務而不僅僅隻是一個任務。
  • 其次,多線程可以讓程序的結構變得簡單。線程在有些場合可以幫助程序員將代碼以簡單優雅的方式進行組織,並減少復雜度。實際上在第一個lab中prime number部分,通過多個進程可以更簡單,方便,優雅的組織代碼。
  • 最後,使用多線程可以通過並行運算,在擁有多核CPU的計算機上獲得更快的處理速度。常見的方式是將程序進行拆分,並通過線程在不同的CPU核上運行程序的不同部分。如果你足夠幸運的話,你可以將你的程序拆分並在4個CPU核上通過4個線程運行你的程序,同時你也可以獲取4倍的程序運行速度。你可以認為XV6就是一個多CPU並行運算的程序。

所以,線程可以認為是一種在有多個任務時簡化編程的抽象。一個線程可以認為是串行執行代碼的單元。如果你寫瞭一個程序隻是按順序執行代碼,那麼你可以認為這個程序就是個單線程程序,這是對於線程的一種寬松的定義。雖然人們對於線程有很多不同的定義,在這裡,我們認為線程就是單個串行執行代碼的單元,它隻占用一個CPU並且以普通的方式一個接一個的執行指令。

除此之外,線程還具有狀態,我們可以隨時保存線程的狀態並暫停線程的運行,並在之後通過恢復狀態來恢復線程的運行。線程的狀態包含瞭三個部分:

  • 程序計數器(Program Counter),它表示當前線程執行指令的位置。
  • 保存變量的寄存器。
  • 程序的Stack(註,詳見5.5)。通常來說每個線程都有屬於自己的Stack,Stack記錄瞭函數調用的記錄,並反映瞭當前線程的執行點。

操作系統中線程系統的工作就是管理多個線程的運行。我們可能會啟動成百上千個線程,而線程系統的工作就是弄清楚如何管理這些線程並讓它們都能運行。

多線程的並行運行主要有兩個策略:

  • 第一個策略是在多核處理器上使用多個CPU,每個CPU都可以運行一個線程,如果你有4個CPU,那麼每個CPU可以運行一個線程。每個線程自動的根據所在CPU就有瞭程序計數器和寄存器。但是如果你隻有4個CPU,卻有上千個線程,每個CPU隻運行一個線程就不能解決這裡的問題瞭。
  • 所以這節課大部分時間我們都會關註第二個策略,也就是一個CPU在多個線程之間來回切換。假設我隻有一個CPU,但是有1000個線程,我們接下來將會看到XV6是如何實現線程切換使得XV6能夠先運行一個線程,之後將線程的狀態保存,再切換至運行第二個線程,然後再是第三個線程,依次類推直到每個線程都運行瞭一會,再回來重新執行第一個線程。

實際上,與大多數其他操作系統一樣,XV6結合瞭這兩種策略,首先線程會運行在所有可用的CPU核上,其次每個CPU核會在多個線程之間切換,因為通常來說,線程數會遠遠多於CPU的核數。

不同線程系統之間的一個主要的區別就是,線程之間是否會共享內存。一種可能是你有一個地址空間,多個線程都在這一個地址空間內運行,並且它們可以看到彼此的更新。比如說共享一個地址空間的線程修改瞭一個變量,共享地址空間的另一個線程可以看到變量的修改。所以當多個線程運行在一個共享地址空間時,我們需要用到上節課講到的鎖。

XV6內核共享瞭內存,並且XV6支持內核線程的概念,對於每個用戶進程都有一個內核線程來執行來自用戶進程的系統調用。所有的內核線程都共享瞭內核內存,所以XV6的內核線程的確會共享內存。

另一方面,XV6還有另外一種線程。每一個用戶進程都有獨立的內存地址空間(註,詳見4.2),並且包含瞭一個線程,這個線程控制瞭用戶進程代碼指令的執行。所以XV6中的用戶線程之間沒有共享內存,你可以有多個用戶進程,但是每個用戶進程都是擁有一個線程的獨立地址空間。XV6中的進程不會共享內存。

在一些其他更加復雜的系統中,例如Linux,允許在一個用戶進程中包含多個線程,進程中的多個線程共享進程的地址空間。當你想要實現一個運行在多個CPU核上的用戶進程時,你就可以在用戶進程中創建多個線程。Linux中也用到瞭很多我們今天會介紹的技術,但是在Linux中跟蹤每個進程的多個線程比XV6中每個進程隻有一個線程要復雜的多。

還有一些其他的方式可以支持在一臺計算機上交織的運行多個任務,我們不會討論它們,但是如果你感興趣的話,你可以去搜索event-driven programming或者state machine,這些是在一臺計算機上不使用線程但又能運行多個任務的技術。在所有的支持多任務的方法中,線程技術並不是非常有效的方法,但是線程通常是最方便,對程序員最友好的,並且可以用來支持大量不同任務的方法。

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

返回顶部