原來定時器中斷是個偽中斷

Spark++發表於2023-03-27

為什麼是偽中斷


      在講主題之前,我們先用一個例子來回顧一下中斷的相關概念。假設你正在閱讀或者工作,這時候你的朋友突然給你打電話或者發簡訊,請求你幫助他解決一個問題,之後你給朋友提了些許建議就繼續自己的閱讀或者工作了。

       在上面這個例子中,這個請求就相當於嵌入式系統中的中斷請求。你此時需要停止你手頭的任務,回答你朋友的問題,這就相當於中斷處理程式的執行過程。當你回答完朋友的問題後,你會回到之前的任務中,繼續完成你手頭的工作,這就相當於嵌入式系統返回到之前被打斷的程式中,繼續執行原來的操作。

       透過以上例子的比對,通常我們認為中斷是執行程式中意料之外的任務,而主程式是執行意料以內的任務。不過在程式設計的世界中,沒有真正意義上的意料之外,如果有些問題的出現對於程式來說是意料之外,只能說是程式碼的健壯性不夠,這是問題,是 BUG。中斷的這種意料之外是對與程式執行而言的,基於某些情況雖然可以被確定,但是在時序與順序的發生上不可被預知

       回到正題,有了上面的思考,定時器中斷還能稱為中斷嗎?定時器中斷是指間隔時間內觸發中斷事件,執行既定操作。從它的執行過程來看,它週期的去執行一些確定性任務,並不是因為某些意料以外的訊號來觸發,從這點來看,這是一種在時間上的同步行為,可被預測的,所以從本質上來說定時器中斷算不上真正意義上的中斷,只能說是偽中斷

 

為什麼要有偽中斷



      定時器的偽中斷本身有何意義,它的存在究竟意欲何為呢?這就需要引入一對雙胞胎——並行併發。這兩個概念一般在作業系統相關的主題中提到的比較多,不過這裡大家不必要理解很深。並行是指在同一時刻,處理多個任務或資料,這些任務同時在不同的處理器或核心中執行。單核的處理器不能實現實現並行,並行是多處理器的許可權,但是單核心可以透過併發來實現偽並行。併發是在一個時間段內,處理多個任務或者資料,這些任務交替執行,看起來好像同時進行。在單核晶片中採用併發諸多優勢,這樣做一方面可以充分發揮處理器的效能,另一方面可以更好應對比較複雜的應用場景。

      繼續回到定時器中斷,它可以看做定時器中斷中的程式與主程式中程式的交替執行,提供了一條與主程式平行的工作流。到這裡這我們終於揭開了定時器中斷的廬山真面目,定時器中斷的底層邏輯就是併發。理解了定時器中斷的本質是併發其實很多東西都明朗了,我們就可以用併發的思路來做開發,這在一定程度上統一了帶有作業系統的併發程式設計,擴充套件了我們的思路。不過兩者在併發的實現,執行等許多方面有一定的差距,那麼之前我們給定時器中斷脫完衣服發現了併發的基本邏輯,現在我們再給定時器中斷穿回其帶有其個性的衣服以讓我們更好把它運用到實踐中去。

     有了定時器中斷後,我們可以把一個定時器週期的時間單獨拉出來看。一個週期的中斷時間可以分為兩部分,一部分時間屬於定時器中斷程式,另一部分屬於主程式。由於中斷程式天生執行的優先順序就高於主程式,因此在程式碼的編寫過程中需要注意雙方程式時間佔比,防止定時器程式對主程式的壓榨,或者說一個定時器週期都不能完成定時器本身的程式碼執行。通常單純裸機的程式碼結構比較簡單,裸機提供的這種併發方式在響應時間、優先順序等許多方面可能並不完美,但是也能很好的處理許多場景,尤其是在有周期性任務的場景。

 

存在即合理



      透過上面的探討我們知道定時器中斷本身就是為了服務於裸機中的併發需要,那麼為什麼要用定時器中斷而不是其它方式來實現呢?在我看來定時器和中斷這兩個工具缺一不可。如果要實現併發,就必須要有程式的切換,但是C語言本身並沒有提供這種功能,只有透過中斷來完成這個過程。那是否可以繞過定時器來實現呢?併發需要系統選擇一個時機進行程式的切換,時機怎麼選,怎麼分配都是個問題,繞過定時器往往需要書寫更加冗雜的切換場景程式碼,對於資源本就不富裕的MCU來說是個不小的負擔。另外對 CPU資源的使用單位本就是用時間來計量,直接使用定時器簡直是得天獨厚。

     由於一些任務學習的原因,時隔兩年再次拿起了32微控制器,看著沉金的板子心中有說不出的小激動。之前在學習裸機過程中我對於主程式、中斷與定時器中斷只知道用法,總是渾渾噩噩的使用,在有了嵌入式Linux的基礎後,總算把這塊的內容統一起來了。技術工具很多,裸機的定時器中斷,作業系統的多執行緒、多程式等等,雖然工具是變的,但是內在的底層邏輯卻是一模一樣,找到這些底層邏輯,熟練地掌握它們是個不錯的學習方向。在思考的過程中也要感謝我的嵌入式設計老師,讓我們本著存在即合理的態度,透過對比來思考事物存在的意義與作用。

相關文章