禁止系统调度
上一节《 多线程导致的临界区问题》中由于 test1 线程被 test2 线程打断,才导致了我们没有得到预期的结果,我们一般可通过关闭中断和调度器上锁这两种简单的途径来禁止系统调度,防止线程被打断,从而保证临界区不被破坏。
1、 关闭中断
线程中关闭中断保护临界区的结构如下:
#include <rtthread.h> #include <stm32f10x.h> #include "test.h" rt_uint32_t g_tmp;/* 定义一个全局变量*/ /* 变量分配4字节对齐 */ ALIGN(RT_ALIGN_SIZE) /* 静态线程的 线程堆栈*/ static rt_uint8_t thread1_stack[512]; static rt_uint8_t thread2_stack[512]; /* 静态线程的 线程控制块 */ static struct rt_thread thread_test1; static struct rt_thread thread_test2; static void test1_thread_entry(void* parameter); static void test2_thread_entry(void* parameter); void demo_thread_creat(void) { rt_err_t result; /* 创建静态线程 : 优先级 16 ,时间片 2个系统滴答 */ result = rt_thread_init(&thread_test1, "test1", test1_thread_entry, RT_NULL, (rt_uint8_t*)&thread1_stack[0], sizeof(thread1_stack), 16, 2); if (result == RT_EOK) { rt_thread_startup(&thread_test1); } /* 创建静态线程 : 优先级 15 ,时间片 1个系统滴答 */ result = rt_thread_init(&thread_test2, "test2", test2_thread_entry, RT_NULL, (rt_uint8_t*)&thread2_stack[0], sizeof(thread2_stack), 15, 1); if (result == RT_EOK) { rt_thread_startup(&thread_test2); } } void test1_thread_entry(void* parameter) { rt_uint32_t i; /* 调度器上锁,上锁后,将不再切换到其他线程,仅响应中断 */ rt_enter_critical(); g_tmp = 0; rt_kprintf("g_tmp=:%d \r\n", g_tmp); for(i=0; i<10000; i++) { g_tmp++; } rt_kprintf("g_tmp=:%d \r\n", g_tmp); /* 调度器解锁 */ rt_exit_critical(); } void test2_thread_entry(void* parameter) { rt_thread_delay(1);// 1 g_tmp++; }
把调度器锁住也能让当前运行的任务不被换出,直到调度器解锁。但和关闭中断有一点不相同的是,对调度器上锁,系统依然能响应外部中断,中断服务例程依然有可能被运行。
所以在使用调度器上锁的方式来做任务同步时,需要考虑好, 任务访问的临界资源是否会被中断服务例程所修改,如果可能会被修改,那么将不适合采用此种方式作为同步的方法。
PS: 上面两种方法的的宗旨其实就是:在临界区内只允许一个线程运行!
除了禁止调度器调度,我们还用线程间通信的方式来保证线程间的同步, 下面我们来介绍 RT-Thread 中的 IPC 对象:信号量、互斥锁、事件、消息队列、邮箱。
时间: 2024-10-13 06:35:00