1.前言
多任务系统中存在一种潜在的风险。当一个任务在使用某个资源的过程中,即还没有完全结束对资源的访问时,便被切出运行态,使得资源处于非一致,不完整的状态
2.并发抢占导致错误的场景
(1)访问外设
如两个任务并发访问LCD
(2)读-改-写操作
ARM7下的赋值操作被编译成多条汇编语言
/* The C code being compiled. */ 155: PORTA |= 0x01; /* The assembly code produced. */ 0x00000264 481C LDR R0,[PC,#0x0070] ; Obtain the address of PORTA 0x00000266 6801 LDR R1,[R0,#0x00] ; Read the value of PORTA into R1 0x00000268 2201 MOV R2,#0x01 ; Move the absolute constant 1 into R2 0x0000026A 4311 ORR R1,R2 ; OR R1 (PORTA) with R2 (constant 1) 0x0000026C 6001 STR R1,[R0,#0x00] ; Store the new value back to PORTA
(3)变量的非原子访问
更新结构体的多个成员变量,或者更新的变量长度超过了架构体系的自然长度,如更新了一个16位机上的32位变量
(4)函数重入
每个任务都单独维护自己的栈空间及其自身在的内存寄存器组中的值
如果一个函数除了访问自己栈空间上分配的数据或是内核寄存器中的数据外,还会访问其它数据,如全局变量等,则这个函数是不可重入的
不可重入的函数如果有多个任务同时访问会造成数据不一致
可重入函数举例
/* A parameter is passed into the function. This will either be passed on the stack or in a CPU register. Either way is safe as each task maintains its own stack and its own set of register values. */ long lAddOneHundered( long lVar1 ) { /* This function scope variable will also be allocated to the stack or a register, depending on compiler and optimization level. Each task or interrupt that calls this function will have its own copy of lVar2. */ long lVar2; lVar2 = lVar1 + 100; /* Most likely the return value will be placed in a CPU register, although it too could be placed on the stack. */ return lVar2; }
不可重入函数举例
/* In this case lVar1 is a global variable so every task that calls the function will be accessing the same single copy of the variable. */ long lVar1; long lNonsenseFunction( void ) { /* This variable is static so is not allocated on the stack. Each task that calls the function will be accessing the same single copy of the variable. */ static long lState = 0; long lReturn; switch( lState ) { case 0 : lReturn = lVar1 + 10; lState = 1; break; case 1 : lReturn = lVar1 + 20; lState = 0; break; } }
3.参考文档
[1] FreeRTOS中文实用教程