程序切換與執行緒切換

2021-10-24 10:51:27 字數 3290 閱讀 6925

為了更好的了解上下文切換,需要我們了解虛擬記憶體的概念。

虛擬記憶體是作業系統為每個程序提供的一種抽象,每個程序都有屬於自己的、私有的、位址連續的虛擬記憶體,當然我們知道最終程序的資料及**必然要放到物理記憶體上,那麼必須有某種機制能記住虛擬位址空間中的某個資料被放到了哪個物理記憶體位址上,這就是所謂的位址空間對映,也就是虛擬記憶體位址與物理記憶體位址的對映關係,那麼作業系統是如何記住這種對映關係的呢,答案就是頁表,頁表中記錄了虛擬記憶體位址到物理記憶體位址的對映關係。有了頁表就可以將虛擬位址轉換為物理記憶體位址了,這種機制就是虛擬記憶體。

每個程序都有自己的虛擬位址空間,程序內的所有執行緒共享程序的虛擬位址空間。

切換虛擬位址空間,切換核心棧和硬體上下文

切換核心棧和硬體上下文

最顯著的效能損耗是將儲存暫存器中的內容

cpu快取記憶體失效

頁表查詢是乙個很慢的過程,因此通常使用cache來快取常用的位址對映,這樣可以加速頁表查詢,這個cache就是tlb.當程序切換後頁表也要進行切換,頁表切換後tlb就失效了,cache失效導致命中率降低,那麼虛擬位址轉換為實體地址就會變慢,表現出來的就是程式執行會變慢

更詳細的來說

切換頁目錄以使用新的位址空間

切換核心棧和硬體上下文

對於linux來說,執行緒和程序的最大區別就在於位址空間,對於執行緒切換,第1步是不需要做的,第2是程序和執行緒切換都要做的。

切換的效能消耗:

執行緒上下文切換和程序上下問切換乙個最主要的區別是執行緒的切換虛擬記憶體空間依然是相同的,但是程序切換是不同的。這兩種上下文切換的處理都是通過作業系統核心來完成的。核心的這種切換過程伴隨的最顯著的效能損耗是將暫存器中的內容切換出。

系統呼叫是在程序上下文中,並沒有tasklet之類的延遲執行,系統呼叫本身可以休眠,這些可以參見核心**

雖然系統呼叫實與其他中斷實現有點類似,通過idt表查詢入口處理函式,但是系統呼叫與其他中斷最大的不同是,系統呼叫是代表當前程序執行的,所以current巨集/task_struct是有意義的,這個休眠可以被喚醒

系統呼叫,異常,中斷(其中中斷是非同步時鐘,異常時同步時鐘),也可以把系統呼叫成為異常

在中斷中執行時依賴的環境,就是中斷上下文(不包括系統呼叫,是硬體中斷)

當乙個程序在執行時,cpu的所有暫存器中的值、程序的狀態以及堆疊中的內容被稱為該程序的上下文

1、首先,這兩個上下文都處於核心空間。

2、其次,兩者的區別在於,程序上下文與當前執行程序密切相關,而中斷上下文在邏輯上與程序沒有關係。

程序上下文主要是異常處理程式和核心執行緒。核心之所以進入程序上下文是因為程序自身的一些工作需要在核心中做。例如,系統呼叫是為當前程序服務的,異常通常是處理程序導致的錯誤狀態等。所以在程序上下文中引用current是有意義的。

核心進入中斷上下文是因為中斷訊號而導致的中斷處理或軟中斷。而中斷訊號的發生是隨機的,中斷處理程式及軟中斷並不能事先**發生中斷時當前執行的是哪個程序,所以在中斷上下文中引用current是可以的,但沒有意義。事實上,對於a程序希望等待的中斷訊號,可能在b程序執行期間發生。例如,a程序啟動寫磁碟操作,a程序睡眠後現在時b程序在執行,當磁碟寫完後磁碟中斷訊號打斷的是b程序,在中斷處理時會喚醒a程序。

上下文這個詞會讓人想到程序的cpu暫存器狀態,但好像進入程序上下文(異常處理系統呼叫)和進入中斷上下文(中斷處理),核心所做的工作沒有太大區別。所以,這兩個上下文的主要區別,我認為在於是否與程序相關。

執行於程序上下文的核心**是可搶占的,但中斷上下文則會一直執行至結束,不會被搶占。因此,核心會限制中斷上下文的工作,不允許其執行如下操作:

(1) 進入睡眠狀態或主動放棄cpu;

由於中斷上下文不屬於任何程序,它與current沒有任何關係(儘管此時current指向被中斷的程序),所以中斷上下文一旦睡眠或者放棄cpu,將無法被喚醒。所以也叫原子上下文(atomic context)。

(2) 占用互斥體;

為了保護中斷控制代碼臨界區資源,不能使用mutexes。如果獲得不到訊號量,**就會睡眠,會產生和上面相同的情況,如果必須使用鎖,則使用spinlock。

(3) 執行耗時的任務;

中斷處理應該盡可能快,因為核心要響應大量服務和請求,中斷上下文占用cpu時間太長會嚴重影響系統功能。在中斷處理例程中執行耗時任務時,應該交由中斷處理例程底半部來處理。

(4) 訪問使用者空間虛擬記憶體。

因為中斷上下文是和特定程序無關的,它是核心代表硬體執行在核心空間,所以在中斷上下文無法訪問使用者空間的虛擬位址

(5) 中斷處理例程不應該設定成reentrant(可被並行或遞迴呼叫的例程)。

因為中斷發生時,preempt和irq都被disable,直到中斷返回。所以中斷上下文和程序上下文不一樣,中斷處理例程的不同例項,是不允許在smp上併發執行的。

(6)中斷處理例程可以被更高階別的irq中斷。(不能巢狀中斷)使用軟中斷,上部分關中斷,也就是禁止巢狀,下半部分使用軟中斷

如果想禁止這種中斷,可以將中斷處理例程定義成快速處理例程,相當於告訴cpu,該例程執行時,禁止本地cpu上所有中斷請求。這直接導致的結果是,由於其他中斷被延遲響應,系統效能下降。

軟中斷是一種延時機制,**執行的優先順序比程序要高,比硬中斷要低。相比於硬體中斷,軟中段是在開中斷的環境中執行的(長時間關中斷對系統的開銷太大), **是執行在中斷/執行緒上下文的,是不能睡眠的,雖然每個cpu都有乙個對應的ksoftirqd/n執行緒來執行軟中斷,但是do_softirq這個函式也還會在中斷退出時呼叫到,因此不能睡眠(中斷上下文不能睡眠的原因是由於排程系統是以程序為基本單位的,排程時會把當前程序的上下文儲存在task_struct這個資料結構中,當程序被排程重新執行時會找到執行的斷點,但是中斷上下文是沒有特定task_struct結構體的,當然現在有所謂的執行緒話中斷,可以滿足在中斷處理函式執行阻塞操作,但是實時性可能會有問題。還有就是中斷代表當前程序執行的概念,個人感覺有點扯淡,畢竟整個核心空間是由所有程序共享的,不存在代表的概念)

上面我們介紹的可延遲函式執行在中斷上下文中(軟中斷的乙個檢查點就是do_irq退出的時候),於是導致了一些問題:軟中斷不能睡眠、不能阻塞。由於中斷上下文出於核心態,沒有程序切換,所以如果軟中斷一旦睡眠或者阻塞,將無法退出這種狀態,導致核心會整個僵死。但可阻塞函式不能用在中斷上下文中實現,必須要執行在程序上下文中,例如訪問磁碟資料塊的函式。因此,可阻塞函式不能用軟中斷來實現。但是它們往往又具有可延遲的特性。

程序切換與執行緒切換

原文 為了控制程序的執行,核心必須有能力掛起正在cpu上執行的程序,並恢復以前掛起的某個程序的執行。這種行為被稱為程序切換 process switch 任務切換 task switch 或上下文切換 content switch 程序切換分兩步 1.切換頁目錄以使用新的位址空間 2.切換核心棧和硬...

執行緒切換與程序切換以及開銷

為了更好的了解上下文切換,需要我們了解虛擬記憶體的概念。虛擬記憶體是作業系統為每個程序提供的一種抽象,每個程序都有屬於自己的 私有的 位址連續的虛擬記憶體,當然我們知道最終程序的資料及 必然要放到物理記憶體上,那麼必須有某種機制能記住虛擬位址空間中的某個資料被放到了哪個物理記憶體位址上,這就是所謂的...

程序切換和執行緒切換

為了控制程序的執行,核心必須有能力掛起正在cpu上執行的程序,並恢復以前掛起的某個程序的執行。這種行為被稱為程序切換 process switch 任務切換 task switch 或上下文切換 content switch 原文 程序切換分兩步 1.切換頁目錄以使用新的位址空間 2.切換核心棧和硬...