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

以下为看视频笔记..........
1.临界区概念

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

不论是硬件临界资源,还是软件临界资源,多个线程必须互斥地对它们进行访问
每个线程中的访问(操作)临界资源的那段代码称为临界区(Critiacl Section),我们每一次只允许一个线程进入临界区。

/* 程序的目的先把全局变量value从0加到10000,在赋值为500.注意顺序。 演示全局变量value为临界区资源,两个线程访问变量value。*/ uint32_t value = https://www.it610.com/article/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 = https://www.it610.com/article/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_tlevel; while(1) { /*关闭中断*/ level = rt_hw_interrupt_disable(); /*以下进入临界区*/ 。。。。。。 /*打开中断*/ rt_hw_interrupt_enable(); } }

我们通过禁止调度的方式保护临界区时,只是将调度器锁住了,但中断是可以正常的响应的。
【RT-Thread学习记录6 临界区保护】关闭中断方式保护临界区时,外部的中断都不能得到有效的响应。选择这两种方式保护临界区时结合实际情况来使用哪种。
3. 临界区保护示例(以关闭中断为例)
在代码中的interrupt_sample.c 中。创建两个线程,线程1是每次打印加10,线程2每次打印加20.Keil模拟通过命令行运行查看。
/* 程序清单:关闭中断进行全局变量的访问 */ #include #include #define THREAD_PRIORITY20 #define THREAD_STACK_SIZE512 #define THREAD_TIMESLICE5/* 同时访问的全局变量 */ 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。

    推荐阅读