目录
临界区:
一次仅只能有一个线程访问的共享资源,可以为一个具体的硬件设备,也可以是一个变量,一个缓冲区,但是,无论软件或硬件,都只能各种线程之间互斥访问。
例如:
rt_uint32_t value=0;
此时全局变量value就是一个共享资源,每个线程中对value访问的代码就是临界区,每次只允许一个线程进入临界区。
void task1(){
value++; //临界区
while(value<50){
rt_kpritf("count is %s\n",value);
}
}
临界区保护方法:
RT-Thread中提供了多种保护临界区的方法,具体分为以下几类
1.禁用系统调度器 2.禁用中断
1.禁用系统调度器
将系统线程调度器锁住,直到临界区相关线程执行结束,再将调度器解锁,即可实现对临界区的保护。
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(level); 中断开启函数
}
}
注意:使用禁用中断时需要先创建变量,然后将中断关闭函数保存在变量中实现中断关闭,在开启中断时将改变量传入开启函数即可。
临界区示例代码:
#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 * 300);
}
}
int main(void)
{
rt_thread_t thread;
/* 创建thread1线程 */
thread = rt_thread_create("thread1", thread_entry, (void *)10,
THREAD_STACK_SIZE,
THREAD_PRIORITY, THREAD_TIMESLICE);
if (thread != RT_NULL)
rt_thread_startup(thread);
/* 创建thread2线程 */
thread = rt_thread_create("thread2", thread_entry, (void *)30,
THREAD_STACK_SIZE,
THREAD_PRIORITY, THREAD_TIMESLICE);
if (thread != RT_NULL)
rt_thread_startup(thread);
return 0;
}
/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(main, interrupt sample);
现象:串口打印对cnt计算的结果,先加10,再加30,再加10依次循坏。
如果不加临界区保护,会导致只跑一个线程,不会交替运行