轉載:Linux kernel rt_mutex的背景和簡介

From: http://blog.chinaunix.net/uid-23146151-id-3074045.htmlcss

最近在看linux rtmutex部分的實現過程,就像他註釋中寫的同樣,仍是比較簡單的。其中比較複雜的部分就是關於任務優先級繼承的部分。html

 

首先介紹優先級反轉的背景。node

何爲優先級反轉?通俗來講就是低優先級的任務搶佔了高優先級的運行權。下面舉出一個優先級翻轉的場景。linux

 

系統中有三個具備不一樣優先級的任務A,B,C。其中A的優先級最高,B次之,C的優先級最低。系統中A與C共享一個資源,此時C任務先就緒得到此資源的使用權限,這時A任務就緒,也想使用此資源,可是因爲C已經在訪問狀態,因此A被阻塞。此時B任務就緒,若是系統中無優先級翻轉處理等機制,那麼B任務就會剝奪C任務的運行權限,從而也就剝奪了A任務的運行權限,這樣稍低優先級的任務就搶佔了高優先級的任務。此種現象就是優先級翻轉問題。數據結構

 

解決優先級翻轉的問題一般有幾種,一種是優先級繼承方式,還有就是天花板方式。函數

  1. 優先級繼承方式是指在有任務阻塞到相應共享資源時,所得到資源的任務繼承被阻塞任務的優先級,固然只是繼承更高的優先級,小於等於的無視。在上例中就爲A得到資源被C阻塞時,C任務繼承A任務的高優先級,這樣B再就緒時就不會搶佔C的運行權,從而就避免了優先級翻轉現象。
  2. 優先級天花板辦法,就是將得到共享資源時,直接提高任務的優先級到能夠得到此種資源的最高優先級。在上例中,當C得到此資源時,直接升到最高的優先級,若是系統中只有A,C使用此資源,那麼就升級到A的優先級,這樣B就緒時也沒法搶佔C的運行權,從而避免了優先級反轉現象。

二者的區別主要在得到優先級提高的時間,前者在有高優先級任務發生阻塞時,後者是直接在得到資源時提高優先級。ui

再補充一個背景介紹,來自:http://blog.csdn.net/kendiv/article/details/1788966spa

1. 優先級反轉(Priority Inversion)
    因爲多進程共享資源,具備最高優先權的進程被低優先級進程阻塞,反而使具備中優先級的進程先於高優先級的進程執行,致使系統的崩潰。這就是所謂的優先級反轉(Priority Inversion)。.net

2. 產生緣由
      其實,優先級反轉是在高優級(假設爲A)的任務要訪問一個被低優先級任務(假設爲C)佔有的資源時,被阻塞.而此時又有優先級高於佔有資源的任務(C)而低於被阻塞的任務(A)的優先級的任務(假設爲B)時,因而,佔有資源的任務就被掛起(佔有的資源仍爲它佔有),由於佔有資源的任務優先級很低,因此,它可能一直被另外的任務掛起.而它佔有的資源也就一直不能釋放,這樣,引發任務A一直沒辦法執行.而比它優先低的任務卻能夠執行.  debug

      因此,一個解決辦法就是提升佔有資源任務的優先級,讓它正常執行,而後釋放資源,以讓任務A能正常獲取資源而得以執行.

3. 解決方案 ( 優先級繼承 / 優先級天花板 )

   目前解決優先級反轉有許多種方法。其中廣泛使用的有2種方法:一種被稱做優先級繼承(priority inheritance);另外一種被稱做優先級極限(priority ceilings)。

  A. 優先級繼承(priority inheritance) 
      優先級繼承是指將低優先級任務的優先級提高到等待它所佔有的資源的最高優先級任務的優先級.當高優先級任務因爲等待資源而被阻塞時,此時資源的擁有者的優先級將會自動被提高.   
    
  B. 優先級天花板(priority ceilings)
      優先級天花板是指將申請某資源的任務的優先級提高到可能訪問該資源的全部任務中最高優先級任務的優先級.(這個優先級稱爲該資源的優先級天花板)   
    
  A 和B的區別: 
    
  優先級繼承,只有當佔有資源的低優先級的任務被阻塞時,纔會提升佔有資源任務的優先級,而優先級天花板,不管是否發生阻塞,都提高.  

 

-------------------------

rtmutex主要數據結構

rt_mutex,就是一個互斥鎖的結構,只有三個元素。

 

  1. struct rt_mutex {
  2.     raw_spinlock_t wait_lock; /* 保護此結構的自旋鎖 */
  3.     struct plist_head wait_list; /* 等待此互斥鎖的全部waiter鏈表 */
  4.     struct task_struct *owner; /* 得到此鎖的task,若是沒有爲NULL */
  5. }

 

rtmutex waiter的數據結構:用於記錄等待互斥鎖得結構

 

  1. struct rt_mutex_waiter {
  2.     struct plist_node    list_entry; /* 用於將此結構鏈接到對應的互斥鎖上 */
  3.     struct plist_node    pi_list_entry; /* 用於將此結構鏈接到互斥鎖全部者上等待鏈表中 */
  4.     struct task_struct    *task;  /* 此waiter所屬的task,也即等待此mutex的task */
  5.     struct rt_mutex        *lock; /* 此waiter等待的mutex */
  6. };

 

主要的數據結構如上所示,後續介紹rtmutex的具體函數調用流程,因爲是mutex,那麼主要從最大需求的三個方面來介紹,一個是init,一個是lock,最後一個就是unlock

1)初始化函數

 

  1. void __rt_mutex_init(struct rt_mutex *lock, const char *name)
  2. {
  3.     lock->owner = NULL;
  4.     raw_spin_lock_init(&lock->wait_lock);
  5.     plist_head_init(&lock->wait_list);
  6.     debug_rt_mutex_init(lock, name);
  7. }

 

此函數已經簡單到不能再簡單了,將rt_mutex中的相關item初始化。

2)lock函數

 

  1. void __sched rt_mutex_lock(struct rt_mutex *lock)
  2. {
  3.     might_sleep();
  4.     rt_mutex_fastlock(lock, TASK_UNINTERRUPTIBLE, 0, rt_mutex_slowlock);
  5. }

 

其中,rt_mutex_fastlock首先嚐試快速得到lock,若是嘗試沒法成功,則調用rt_mutex_slowlock 繼續得到鎖。

3)unlock函數

 

  1. void __sched rt_mutex_unlock(struct rt_mutex *lock)
  2. {
  3.     rt_mutex_fastunlock(lock, rt_mutex_slowunlock);
  4. }

 

此函數與上述lock函數同樣,首先嚐試快速的unlock,若是不符合條件,那麼再調用rt_mutex_slowunlock函數完成解鎖操做。

 

內部機制,我是很想好好闡述出來的,可是因爲本身表達能力有限,等後續總結好了,再更改此篇博客。想寫一篇好的技術博客真TM難啊。看懂一個東西簡單,講明白一個東西真TM難,想要理解爲啥這麼搞更TM難。

相關文章
相關標籤/搜索