RT-Thread学习记录6 临界区保护

以下为看视频笔记..........

1.临界区概念

 

临界资源是指一次仅允许一个线程访问的共享资源。它可以是一个具体的硬件设备(如打印机等),也可以是一个变量、一个缓冲区。

不论是硬件临界资源,还是软件临界资源,多个线程必须互斥地对它们进行访问

每个线程中的访问(操作)临界资源的那段代码称为临界区(Critiacl Section),我们每一次只允许一个线程进入临界区。

/*
程序的目的先把全局变量value从0加到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 
#include 

#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。

你可能感兴趣的:(rt_thread)