協程 執行緒和執行上下文

2021-07-26 16:51:57 字數 1499 閱讀 3317

摘要: 本文介紹協程、執行緒及它們執行的上下文等概念,同時給出注意事項。協程是使用者級的任務排程,執行緒是核心級的任務排程,而任務排程過程都涉及到上下文切換(儲存與恢復),本文將從較為深刻的角度來闡述這些概念,及其相互關係。

執行緒在現代的系統裡扮演的角色很重要,幾乎乙個現代一點的,稍微複雜大型一點的程式,往往都會引入執行緒,實現某種意義的並行。執行緒存在廣泛的支援,從作業系統,到編譯器,再到語言的定義與實現者,他們都在努力讓執行緒更好用,也有更少的限制。相反協程的現實要慘淡很多,在作業系統那裡很少有協程的影子;只有windows裡,存在乙個協程的實現——fiber(在那裡它被稱為纖程)。

從概念上來說,執行緒和協程最大的區別就是排程方式不同——執行緒是被動排程的,協程是主動排程的。也就是說,執行緒什麼時候執行,什麼時候不執行,完全是os決定,執行緒是os的菜,程式設計師最多只能主動讓執行緒停下來,卻很難讓執行緒主動執行起來。相反協程的執行與停止完全由程式設計師決定,何時執行、何時停止簡單地呼叫乙個協助方法就可以完成。因為執行緒是被動排程的,所以執行緒需要大量同步方法;而協程是主動排程的,所以協程之間的同步可以很自然完成——該停該跑——就這簡單直接。

協程的概念很完美,使用可能也很方便。但是因為一些我還不了解的原因,在c/c++裡並沒有廣泛使用協程庫可用,這是因為現在的os和編譯器無法很好地支援協程的實現;這也許是歷史原因,執行緒在概念上與執行緒不相矛盾,但它的許多實現方式限制了實現通用安全的協程。在c語言和unix草莽朝代,實現乙個協程要比實現乙個函式(協程的一種特例)更困難,而對於當時來說,函式已經完全夠用了,如此協程被冷淡了。

在使用者層協程被死死地限制了,可是在linux核心裡,它卻乙個基本的構件——核心執行緒,在更多的時候,更乙個協程。當然這句話是我自己說,在我很有限的linux核心經驗上說的,極有可能是錯誤的。

執行緒是作業系統實現的,也是作業系統的排程單位。我們知道,所謂排程就是作業系統根據一些規則決定在何時中止乙個執行緒操作,並在乙個恰當的時候再喚醒這個執行緒。這裡有個自然的問題,就是作業系統怎麼實現中止與喚醒操作的?其時停止與喚醒操作都離不開cpu的支援,cpu在硬體上實現了中斷機制,os使用中斷機制實現了執行緒排程。os可以告訴cpu,每過100ms(毫秒)或10ms你就呼叫一下一段**——這就是所謂的時鐘中斷例程,os在這一小段**裡實現了執行緒的中止與喚醒。在這段**裡,os通常會做這些事:

在上面的說明,我們看到一次儲存狀態和一次恢復狀態,所謂狀態就是上下文(狀態),而這個一次儲存和一次恢復的過程稱為一次上下文切換——大概意思就是說,剛才cpu在幹這塊的活,現在它又切換到另一塊地方幹活了。

現在我們知道上下文切換,以及os是如何實現上下文切換的了,那麼有乙個問題,就是程式設計師能不能在自己的程式裡使用與os相同功能的**,在自己的程式進行上下文切換?答案是: 完全可以。事實上,這就是實現協程的基本方法。程式在執行的時候是沒有函式這些概念的,諸如函式這些概念都上層語言及編譯器實現的抽象概念,cpu不認識。cpu只認識指令及指令操作的位址。

了解 c++ boost 庫的人一定知道它最近新加了兩個庫: context 和 coroutine —— 看這個名字就知道,前者是實現了上下文切換的,後者是利用前者實現了使用者態協程的。

提公升 執行上下文和執行上下文棧

提公升 1.變數宣告提公升 通過var定義 宣告 的變數,在之前就可以直接使用,但不會被賦值 值 undefined 2.函式宣告提公升 通過function宣告的函式,在之前就可以直接呼叫 函式表示式不能在定義前呼叫 值 函式定義 物件 3.問題 變數提公升和函式提公升怎麼產生的?變數提公升簡單理...

執行上下文

1.分類 位置 全域性 函式 區域性 2.全域性執行上下文 在執行全域性 前將window確定為全域性執行上下文 對全域性資料進行預處理 var定義的全域性變數 undefined,新增為window的屬性 function宣告的全域性函式 賦值 fun 新增為window的方法 this 賦值 w...

this執行上下文

this的指向為 誰呼叫當前this所在的函式,this就指向誰。也就是說,當前呼叫函式的那個物件自身就是this,就是當前的執行上下文。被滑鼠事件,鍵盤事件等觸發的函式 叫做事件處理函式,事件處理函式的this指向事件源 觸發事件的節點 事件處理函式第乙個引數是事件物件 備註 有名函式的this指...