界区( Critical Section),每次只准许一个线程进入临界区,进入后不允许其他线程进入。多线程程序的开发方式不同于裸机程序,多个线程在宏观上是并发运行的,因此使用一个共享资源是需要注意,否则就可能出现错误的运行结果。
#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; /* 创建静态线程 : 优先级 15 ,时间片 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); } /* 创建静态线程 : 优先级 16 ,时间片 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; 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); } void test2_thread_entry(void* parameter) { rt_thread_delay(100);// 1 rt_thread_delay(100);两种情况下得到两张图片
g_tmp++;
}
结果分析:
在 test1 线程的 for 循环中我们对 i 做了 10000 次累加,如果没有其他线程的“干预”,那么全局变量 g_tmp 的值应该是 10000,现在的输出结果是 10001,这意味全局变量 g_tmp 的值被线程 2 修改过。整个程序运行过程中各个线程的状态变化是这样的: rt_application_init 中创建两个线程之后,由于 test2 线程的优先级比 test1 线程的优先级高,因此 test2 线程先运行,其线程处理函数第一句为 rt_thread_delay(1), 这会使得 test2 线程被挂起,挂起时间为 1 个时间片,在 test2 线程挂起的这段时间中, test1 线程是所有就绪态线程中优先级最高的线程,因此被内核调度运行。 在 test1 线程执行了一部分代码后, 1 个 tick 时间到, test2 线程被唤醒,从而成为所有就绪线程中优先级最高的线程,因此会被立刻调度运行, test1 线程被 test2 线程抢占, test2 线程中对全局变量 g_tmp 做累加操作,接下来 test2 线程执行完毕, test1 线程再次被调度运行,根据程序的运行结果可以看出,此时 test1 线程继续执行,但是我们并不知道此时 test1 线程大致是从什么地方在开始执行的,从最后的输出结果来看,只能得知此时test1 线程还没有执行到第二条 rt_kprintf 输出语句。最后 test1 线程再次打印全局变量 g_tmp的值,其值就应该是 10001。当 test2线程中的第一句为 rt_thread_delay(100)的时候,在 test2线程休眠的整个时间里,test1 线程都已经执行完毕,因此最后的输出结果为 10000。
从以上可以看到: 当公共资源在多个线程中公用时,如果缺乏必要的保护错误,最后的输出结果可能与预期的结果完全不同。为了解决这种问题,需要引入线程间通信机制,这就
是所谓的 IPC 机制( Inter-Process Communication)。