以下为看视频笔记..........
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。
推荐阅读
- RT-Thread|RT-Thread 入门学习笔记(vsnprintf来替代rt_vsnprintf来打印浮点)
- RT-Thread 内核实验 1 任务的基本管理
- #|RT_Thread+STM32开发,线程栈大小分配问题