以下爲看視頻筆記..........
1.臨界區概念
臨界資源是指一次僅允許一一個線程訪問的共享資源。它可以是一個具體的硬件設備(如打印機等),也可以是一個變量、一個緩衝區。
不論是硬件臨界資源,還是軟件臨界資源,多個線程必須互斥地對它們進行訪問
每個線程中的訪問(操作)臨界資源的那段代碼稱爲臨界區(Critiacl Section),我們每一次只允許一個線程進入臨界區。
/*
程序的目的先把全局變量value值加到10000,在賦值爲500.注意順序。
演示全局變量value爲臨界區資源,兩個線程訪問變量value。
*/
uint32_t value = 0; //一個變量爲臨界資源
void thread1_entry(void *para) //線程1 訪問全局變量value,進行加價操作
{
uint32_t i=0;
for(i=0;i<10000;i++)
{
rt_kprintf("%d\\r\rn",value);
value++;
}
}
void thread2_entry(void *para) //線程2 訪問全局變量value進行值的改寫
{
rt_thread_delay(50);
value = 500;
}
爲了以上value值能夠先加到10000後在賦值爲500,每次操作我們要有臨界區保護操作。
2. 臨界區保護
RT—Thread提供了多種途徑來進行臨界區保護
1關閉系統調度保護臨界區:禁止調度,關閉中斷
2互斥特性保護臨界區:信號量,互斥量
1.禁止調度
禁止調度,即是把調度器鎖住,不讓其進行線程切換。這樣就能保證當前運行的任務不被換出,直到調度器解鎖,所以禁止調度是常用的臨界區保護方法,達到共享臨界資資源的目的,兩個API如下
void thread_entry(void *parameter)
{
while(1)
{
/*調度器上鎖,上鎖後不再切換到其他線程,僅響應中斷*/
rt_enter_critical();
/*以下進入臨界區*/
。。。。。。
/*調度器解鎖*/
rt_exit_critical();
}
}
2.關閉中 斷
因爲所有線程的調度都是建立在中斷的基礎上的,所以,當我們關閉中斷後,系統將不能再進行調度,線程自身也自然不會被其他線程搶佔了。
void thread_entry(void *parameter)
{
rt_base_t level;
while(1)
{
/*關閉中斷*/
level = rt_hw_interrupt_disable();
/*以下進入臨界區*/
。。。。。。
/*打開中斷*/
rt_hw_interrupt_enable();
}
}
我們通過禁止調度的方式保護臨界區時,只是將調度器鎖住了,但中斷是可以正常的響應的。
關閉中斷方式保護臨界區時,外部的中斷都不能得到有效的響應。選擇這兩種方式保護臨界區時結合實際情況來使用哪種。
3. 臨界區保護示例(以關閉中斷爲例)
在代碼中的interrupt_sample.c 中。創建兩個線程,線程1是每次打印加10,線程2每次打印加20.Keil模擬通過命令行運行查看。
/* 程序清單:關閉中斷進行全局變量的訪問 */
#include <rthw.h>
#include <rtthread.h>
#define THREAD_PRIORITY 20
#define THREAD_STACK_SIZE 512
#define THREAD_TIMESLICE 5
/* 同時訪問的全局變量 */
static rt_uint32_t cnt;
void thread_entry(void *parameter)
{
rt_uint32_t no;
rt_uint32_t level;
no = (rt_uint32_t) parameter;
while (1)
{
/* 關閉中斷 */
level = rt_hw_interrupt_disable();
cnt += no;
/* 恢復中斷 */
rt_hw_interrupt_enable(level);
rt_kprintf("protect thread[%d]'s counter is %d\n", no, cnt);
rt_thread_mdelay(no * 10);
}
}
/* 用戶應用程序入口 */
int interrupt_sample(void)
{
rt_thread_t thread;
//創建兩個線程的優先級和時間片都一樣的,所以會根據時間片來調度
/* 創建t1線程 */
thread = rt_thread_create("thread1", thread_entry, (void *)10,
THREAD_STACK_SIZE,
THREAD_PRIORITY, THREAD_TIMESLICE);
if (thread != RT_NULL)
rt_thread_startup(thread);
/* 創建t2線程 */
thread = rt_thread_create("thread2", thread_entry, (void *)20,
THREAD_STACK_SIZE,
THREAD_PRIORITY, THREAD_TIMESLICE);
if (thread != RT_NULL)
rt_thread_startup(thread);
return 0;
}
/* 導出到 msh 命令列表中 */
MSH_CMD_EXPORT(interrupt_sample, interrupt sample);
記住操作流程和相關的API。