1. 程式人生 > 其它 >中斷中為何不能使用訊號量,中斷上下文為何不能睡眠

中斷中為何不能使用訊號量,中斷上下文為何不能睡眠

1、中斷中為何不能使用訊號量?

答: 訊號量會導致睡眠。

 

2、中斷上下為何不能睡眠?

以下為轉載: http://blog.chinaunix.NET/uid-7332782-id-3213376.html

 

中斷髮生以後,CPU跳到核心設定好的中斷處理程式碼中去,由這部分核心程式碼來處理中斷。這個處理過程中的上下文就是中斷上下文。 

     為什麼可能導致睡眠的函式都不能在中斷上下文中使用呢? 首先睡眠的含義是將程序置於“睡眠”狀態,在這個狀態的程序不能被排程執行。然後,在一定的時機,這個程序可能會被重新置為“執行”狀態,從而可能被排程執行。 可見,“睡眠”與“執行”是針對程序而言的,代表程序的task_struct結構記錄著程序的狀態。核心中的“排程器”通過task_struct對程序進行排程。 
     但是,中斷上下文卻不是一個程序,它並不存在task_struct,所以它是不可排程的。所以,在中斷上下文就不能睡眠。 

     那麼,中斷上下文為什麼不存在對應的task_struct結構呢? 
     中斷的產生是很頻繁的(至少每毫秒(看配置,可能10毫秒或其他值)會產生一個時鐘中斷),並且中斷處理過程會很快。如果為中斷上下文維護一個對應的task_struct結構,那麼這個結構頻繁地分配、回收、並且影響排程器的管理,這樣會對整個系統的吞吐量有所影響。 

     但是在某些追求實時性的嵌入式linux中,中斷也可能被賦予task_struct結構。這是為了避免大量中斷不斷的巢狀,導致一段時間內CPU總是執行在中斷上下文,使得某些優先順序非常高的程序得不到執行。這種做法能夠提高系統的實時性,但是代價中吞吐量的降低   轉載:https://blog.csdn.net/Qinus/article/details/84404334  

如果被保護的共享資源只在程序上下文和軟中斷上下文訪問,那麼當在程序上下文訪問共享資源時,可能被軟中斷打斷,從而可能進入軟中斷上下文來對被保護的共享資源訪問,因此對於這種情況,對共享資源的訪問必須使用spin_lock_bh和spin_unlock_bh來保護。

當然使用spin_lock_irq和spin_unlock_irq以及spin_lock_irqsave和spin_unlock_irqrestore也可以,它們失效了本地硬中斷,失效硬中斷隱式地也失效了軟中斷。但是使用spin_lock_bh和spin_unlock_bh是最恰當的,它比其他兩個快。(Loon:這不是快不快的問題,而是強制造成CPU失效硬中斷,帶來效能的損失。)

 

如果被保護的共享資源只在程序上下文和tasklet或timer上下文訪問,那麼應該使用與上面情況相同的獲得和釋放鎖的巨集,因為tasklet和timer是用軟中斷實現的。

 

如果被保護的共享資源只在一個tasklet或timer上下文訪問,那麼不需要任何自旋鎖保護,因為同一個tasklet或timer只能在一個CPU上執行,即使是在SMP環境下也是如此。實際上tasklet在呼叫tasklet_schedule標記其需要被排程時已經把該tasklet繫結到當前CPU,因此同一個tasklet決不可能同時在其他CPU上執行。timer也是在其被使用add_timer新增到timer佇列中時已經被幫定到當前CPU,所以同一個timer絕不可能執行在其他CPU上。

 

如果被保護的共享資源只在兩個或多個tasklet或timer上下文訪問,那麼對共享資源的訪問僅需要用spin_lock和spin_unlock來保護,不必使用_bh版本,因為當tasklet或timer執行時,不可能有其他tasklet或timer在當前CPU上執行。

 

如果被保護的共享資源只在一個軟中斷(tasklet和timer除外)上下文訪問,那麼這個共享資源需要用spin_lock和spin_unlock來保護,因為同樣的軟中斷可以同時在不同的CPU上執行。(Loon:這和tasklet和timer不同,上面已經解釋過,同一個tasklet和timer只能繫結到一個CPU上執行,不能同時在其他CPU上執行。軟中斷沒有這個限制。)

 

如果被保護的共享資源在兩個或多個軟中斷上下文訪問,那麼這個共享資源當然更需要用spin_lock和spin_unlock來保護,不同的軟中斷能夠同時在不同的CPU上執行。

 

如果被保護的共享資源在軟中斷(包括tasklet和timer)或程序上下文和硬中斷上下文訪問,那麼在軟中斷或程序上下文訪問期間,可能被硬中斷打斷,從而進入硬中斷上下文對共享資源進行訪問,因此,在程序或軟中斷上下文需要使用spin_lock_irq和spin_unlock_irq來保護對共享資源的訪問。

而在中斷處理控制代碼中使用什麼版本,需依情況而定,如果只有一箇中斷處理控制代碼訪問該共享資源,那麼在中斷處理控制代碼中僅需要spin_lock和spin_unlock來保護對共享資源的訪問就可以了。因為在執行中斷處理控制代碼期間,不可能被同一CPU上的軟中斷或程序打斷。但是如果有不同的中斷處理控制代碼訪問該共享資源,那麼需要在中斷處理控制代碼中使用spin_lock_irq和spin_unlock_irq來保護對共享資源的訪問。

在使用spin_lock_irq和spin_unlock_irq的情況下,完全可以用spin_lock_irqsave和spin_unlock_irqrestore取代,那具體應該使用哪一個也需要依情況而定,如果可以確信在對共享資源訪問前中斷是使能的,那麼使用spin_lock_irq更好一些。因為它比spin_lock_irqsave要快一些,但是如果你不能確定是否中斷使能,那麼使用spin_lock_irqsave和spin_unlock_irqrestore更好,因為它將恢復訪問共享資源前的中斷標誌而不是直接使能中斷。

當然,有些情況下需要在訪問共享資源時必須中斷失效,而訪問完後必須中斷使能,這樣的情形使用spin_lock_irq和spin_unlock_irq最好。

 

spin_lock用於阻止在不同CPU上的執行單元對共享資源的同時訪問以及不同程序上下文互相搶佔導致的對共享資源的非同步訪問,而中斷失效和軟中斷失效卻是為了阻止在同一CPU上軟中斷或中斷對共享資源的非同步訪問。

 

--

Loon:這裡只是列舉各種情形下spinlock的使用方法,而對spinlock的深度理解請參考LDD3和核心原始碼。

轉載: https://blog.csdn.net/azloong/article/details/8964474