執行緒的排程,都是建立在中斷的基礎上的,當我們關閉中斷,系統將不能進行排程了,還有我們可以禁止排程器排程來保護臨界資源。除了這些我們還用執行緒間通訊的方式保護執行緒間的同步。
ipc機制(inter-process communication)----意思是程序間通訊。rt-thread中ipc物件有:訊號量、互斥鎖、事件、訊息佇列、郵箱。
1---
執行緒搶占導致臨界區問題
兩個執行緒共同占用乙個全域性變數,假設執行緒
thread1
和thread2
優先順序分別是7和
4,但是程式執行時,
thread2
會先執行,但是執行緒
thread2
中有延時(且非常短),這是
thread1
得以執行,但是
thread1
執行緒並沒有執行完畢,這時候
thread2
的延時到了且優先順序高於
thread1
,thread2
執行緒繼續執行,但是這時候它就改變了全域性變數的值,當
thread1
再次執行的時候,已經是更新後的值了。最後的輸出結果就會跟預期的結果完全不同了,為了解決這種問題,我們引入了
ipc機制。
2---
訊號量基本使用
訊號量像一把鑰匙,任務要執行下去,需先拿到這把鑰匙。
申請訊號量的任務是再說:「把鑰匙給我,如果誰在正在用,我只好等!」
詳細看rt-thread
核心分析:
訊號量有兩種操作:
take(獲取)
和release(
釋放),
當乙個執行緒呼叫
take
操作時,他要麼得到資源然後將訊號量減一,要麼一直等下去
(指放入阻塞佇列
),直到訊號量大於等於一時,
release(釋放)
實際上是在訊號量上執行加操作,
take(獲取)
實際上是在訊號量上執行減操作。
rt-thread
中訊號量有靜態和動態之分(同靜態執行緒、動態執行緒),和訊號量有關的操作如下:
初始化——
rt_sem_init()
(對應靜態訊號量);
建立——
rt_sem_create()
(對應動態訊號量);
獲取——
rt_sem_take();
釋放——
rt_sem_release();
脫離——
rt_sem_detach();
(對應靜態訊號量);
刪除——
rt_sem_delete();
(對應動態訊號量);
3---
用訊號量實現任務之間的排程 1.
建立乙個訊號量,且初始值設為
0,如下:
result= rt_sem_init(&sem, "sem", 0, rt_ipc_flag_fifo);
f (result != rt_eok)
2.有執行緒申請得到訊號量,**如下:(由於初始值為
0,是無效的(訊號量大於
0有效),所以該執行緒只能等待。)
staticvoid rt_thread_entry2(void* parameter)}}
3.執行緒
thread1
釋放訊號量
staticvoid rt_thread_entry1(void* parameter)
rt_thread_delay(rt_tick_per_second/10);}}
release
(釋放)訊號量,這裡訊號量的值就會加
1,變成有效的了,當此執行緒執行到
delay
函式時,系統就會執行
thread2
執行緒,此時訊號量也是有效的,所以它就會獲取訊號量,使訊號量的值減
1。從而列印資訊。
4---
使用訊號量解決生產者消費者問題
生產者消費者問題是乙個著名的執行緒同步問題,
該問題描述如下:有乙個生產者在生產產品,這些產品將提供給若干個消費者去消費。為了使生產者和消費者能併發執行,在兩者之間設定乙個具有多個位置的緩衝區,生產者將它生產的產品放入緩衝區中,消費者可以從緩衝區中取走產品進行消費。生產者和消費者之間必須保持同步,即當緩衝區為空時,消費者需要被阻塞(即掛起)直到生產者者生產出產品並放入緩衝區;當緩衝區滿時,生產者則需要被阻塞直到消費者衝緩衝區取走產品使得緩衝區有至少乙個空位。
注意:
從緩衝區取出產品和向緩衝區投放產品的過程為臨界區,必須是互斥進行的,可以使用互斥量
(mutex
)、二值訊號量或排程器上鎖實現臨界區互斥。
當緩衝區不滿時,生產者才可以向緩衝區中投放產品;當緩衝區不空時,消費者才可以從緩衝區中取出產品消費,因此這意味著生產者和消費者各自獲取乙個訊號量。
1.初始化三個訊號量
rt_err_tresult;
/*初始化
3個訊號量*/
result = rt_sem_init(&sem_lock , "lock",1, rt_ipc_flag_fifo);
if (result != rt_eok)
goto _error;
result = rt_sem_init(&sem_empty,"empty", maxsem, rt_ipc_flag_fifo);
if (result != rt_eok)
goto _error;
result = rt_sem_init(&sem_full , "full",0, rt_ipc_flag_fifo);
if (result != rt_eok)
goto _error;
2.建立三個執行緒,
producer
的優先順序為10。
consumer1
和consumer2
的優先順序
11。**省略。
看看生產者入口函式
生產者執行緒需要先獲取
sem_empty
,當成功獲取,這表示緩衝區有空位,即可以向緩衝區投放「產品」。注意修改緩衝區的**為臨界區,因此使用二值訊號量
sem_lock
將整個臨界區保護起來。
------
消費者入口
為了減少**,兩個消費者採用相同的執行緒入口函式。通過引數
parameter
來區分開來
消費者執行緒需要獲取
sem_full
訊號量,如果其值為
0則意味著緩衝區沒有產品。該執行緒無妨獲取訊號量而被阻塞。如果成功獲取
sem_full
訊號量,表示緩衝區非空,即可取出產品消費。之後,執行釋放
sem_emptry
,即緩衝區空位數目增加乙個。 3.
兩個消費者之間的輪詢。
由於兩個消費者的優先順序相同,只能按照時間片輪換執行。這兩個執行緒執**況分析起來挺複雜的,現在我也沒有徹底的分析清楚。
總結:用二值訊號量實現保護臨界區不被破壞,用計數訊號量,實現多個執行緒間的同步。
這裡有乙個解決哲學家就餐問題的例子,我看的也不是太明白了,所以就不細研究了,詳細請看官方文件:
5---
互斥鎖
互斥鎖跟二值訊號量很相似,
rt-thread
中互斥鎖也有靜態和動態之分,和互斥鎖有關的操作如下:
初始化——
rt_mutex_init()
(對應靜態互斥鎖)
建立——
rt_mutex_create()
(對應動態互斥鎖)
獲取——
rt_mutex_take();
釋放——
rt_mutex_release();
脫離——
rt_mutex_detach()
(對應靜態互斥鎖)
刪除——
rt_mutex_delete()
(對應動態互斥鎖)
互斥鎖跟訊號量的區別是:
1.訊號量**都可以釋放,但互斥鎖只有獲得了其控制權的執行緒才可以釋放,即:只有「鎖上」它的那個執行緒才有「鑰匙」開啟它。 2.
訊號量可能導致執行緒優先順序反轉,而互斥鎖可通過優先順序繼承的方法解決優先順序反轉的問題。
詳細請看官方文件和例程:
如果有人細細的研究
rt-thread
的互斥鎖的核心原始碼,請看原始碼分析:
6---郵箱
rt-thread
的郵箱中共可存放固定條數的郵件,郵箱容量在建立時設定,每個郵件大小為
4個位元組(正好是乙個指標的大小)。
傳送執行緒向郵箱中傳送郵件,等待執行緒接收郵件,如果等待接收到郵件則得以執行,否則等待。
郵件的操作跟上面的相似,也有動態和靜態之分。
7-訊息佇列
這個跟郵箱差不多,而郵件只能容納固定的
4位元組內容,訊息佇列能夠接收不固定長度的訊息。
總結:在使用
ipc物件時,在其等待獲取資源時,都會早餐執行緒阻塞
(除非以非等待的方式獲取
)所以,
不要在中斷服務程式中去嘗試去執行獲取訊號量、互斥鎖、郵箱、訊息佇列的操作。
作業系統之作業系統引論
掌握作業系統的概念 特徵 功能和提供的服務,作業系統的發展與分類 作業系統是計算機硬體與使用者的橋梁,是計算機硬體上的的第一層軟體,是對硬體系統的首次擴充.作業系統是一組控制和管理計算機硬體和軟體資源.合理地對各類作業 job 進行排程,以及方便使用者的程式的集合.無作業系統 單批道作業系統 多批道...
Linux作業系統修改ip
修改 etc sysconfig network scripts ifcfg eth0 device name 其中,name是物理裝置名。ipaddr addr,其中,addr是ip位址。netmask mask,其中,mask是網路掩碼值。network addr,其中addr是網路位址。bro...
作業系統之PV操作
在計算機作業系統中,pv操作是程序管理中的難點。首先應弄清pv操作的含義 pv操作由p操作原語和v操作原語組成 原語是不可中斷的過程 對訊號量進行操作,具體定義如下 p s 將訊號量s的值減1,即s s 1 如果s 0,則該程序繼續執行 否則該程序置為等待狀態,排入等待佇列。v s 將訊號量s的值加...