RT-Thread學習記錄6 臨界區保護

以下爲看視頻筆記..........

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。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章