我在FreeRTOS(FreeRTOSV7.4.0\FreeRTOS\Source\tasks.c)中找到了一些代码:
void vTaskSuspendAll( void )
{
/* A critical section is not required as the variable is of type
portBASE_TYPE. */
++uxSchedulerSuspended;
}
Run Code Online (Sandbox Code Playgroud)
它明确表示不需要保护,因为类型是"portBASE_TYPE",这是一个"长"类型.我的理解是它假设这种类型的自增量是原子的.但是在我拆开它后我找不到任何证据,它是一个普通的load-> add-> store.那是一个问题吗?
void vTaskSuspendAll( void )
{
/* A critical section is not required as the variable is of type
portBASE_TYPE. */
++uxSchedulerSuspended;
4dc: 4b03 ldr r3, [pc, #12] ; (4ec <vTaskSuspendAll+0x10>)
4de: f8d3 2118 ldr.w r2, [r3, #280] ; 0x118
4e2: 1c50 adds r0, r2, #1
4e4: f8c3 0118 str.w r0, [r3, #280] ; 0x118
4e8: 4770 bx lr
4ea: bf00 nop
4ec: 00000000 .word 0x00000000
000004f0 <xTaskGetTickCount>:
return xAlreadyYielded;
}
Run Code Online (Sandbox Code Playgroud)
正如你所记录的那样,这不是原子的.但是在严格意义上它仍然可以是"线程安全的":a long
不能处于不一致的状态.这里危险的程度,如果n
线程调用vTaskSuspendAll
,然后uxSchedulerSuspended
将任意位置1和2之间递增n
.
但是,如果变量不需要完美,那么这可能是完全正常的,就像用户要求暂停多少次的跟踪器一样.有"线程安全"的意思是"这个操作产生相同的结果,无论它的调用是如何交错的",并且"线程安全"意味着"如果从多个线程调用它,则不会爆炸".
小智 6
这个操作不是原子的,但它没有说它是.但是,代码是线程安全的,但您必须非常熟悉代码正在做什么,以及它如何适应调度程序的设计以了解它.其他任务是否修改了加载和存储之间的变量并不重要,因为当执行任务下次运行时,它将找到与执行原始加载时相同状态的变量(因此修改和写入部分仍然一致且有效).
作为之前发布的注释,long不能处于不一致状态,因为它是运行它的体系结构的基本类型.但是请考虑如果代码在8位机器(或16位)上运行并且变量为32位会发生什么.然后它将不是线程安全的,因为一次完整的32位将被修改为字节或字,而不是一次修改.在这种情况下,一个字节可能被加载到一个寄存器中,经过修改,然后在发生上下文切换时写回RAM(其他三个字节保持不变).如果执行的下一个任务读取相同的变量,它将读取一个已修改的字节和三个没有的字节 - 并且您有一个主要问题.