Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/66.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 哪些变量类型/大小是STM32微控制器上的原子变量?_C_Arm_Atomic_Stm32_Freertos - Fatal编程技术网

C 哪些变量类型/大小是STM32微控制器上的原子变量?

C 哪些变量类型/大小是STM32微控制器上的原子变量?,c,arm,atomic,stm32,freertos,C,Arm,Atomic,Stm32,Freertos,以下是STM32微控制器上的数据类型: 这些微控制器使用32位ARM核心处理器 哪些数据类型具有自动原子读取和原子写入访问权限 我很确定所有32位数据类型都可以(因为处理器是32位的),而所有64位数据类型都不能(因为读或写一个64位字至少需要2个处理器操作),但是bool(1字节)和uint16\u t/int16\u t(2字节)呢 上下文:我在STM32上的多个线程之间共享变量(单核,但多线程,或者在中称为“任务”),我需要知道是否需要通过关闭中断、使用互斥体等来强制原子访问 更新: 参考

以下是STM32微控制器上的数据类型:

这些微控制器使用32位ARM核心处理器

哪些数据类型具有自动原子读取和原子写入访问权限

我很确定所有32位数据类型都可以(因为处理器是32位的),而所有64位数据类型都不能(因为读或写一个64位字至少需要2个处理器操作),但是
bool
(1字节)和
uint16\u t
/
int16\u t
(2字节)呢

上下文:我在STM32上的多个线程之间共享变量(单核,但多线程,或者在中称为“任务”),我需要知道是否需要通过关闭中断、使用互斥体等来强制原子访问

更新:

参考此示例代码:

volatile bool shared_bool;
volatile uint8_t shared u8;
volatile uint16_t shared_u16;
volatile uint32_t shared_u32;
volatile uint64_t shared_u64;
volatile float shared_f; // 32-bits
volatile double shared_d; // 64-bits

// Task (thread) 1
while (1)
{
    // Write to the values in this thread.
    // What I write to each variable will vary. Since other threads
    // are reading these values, I need to ensure my *writes* are atomic, or else
    // I must use a mutex to prevent another thread from reading a variable in the middle
    // of this thread's writing.
    shared_bool = true;
    shared_u8 = 129;
    shared_u16 = 10108;
    shared_u32 = 130890;
    shared_f = 1083.108;
    shared_d = 382.10830;
}

// Task (thread) 2
while (1)
{
    // Read from the values in this thread.
    // What thread 1 writes into these values can change at any time, so I need to ensure
    // my *reads* are atomic, or else I'll need to use a mutex to prevent the other 
    // thread from writing to a variable in the midst of reading
    // it in this thread.
    if (shared_bool == whatever)
    {
        // do something
    }
    if (shared_u8 == whatever)
    {
        // do something
    }
    if (shared_u16 == whatever)
    {
        // do something
    }
    if (shared_u32 == whatever)
    {
        // do something
    }
    if (shared_u64 == whatever)
    {
        // do something
    }
    if (shared_f == whatever)
    {
        // do something
    }
    if (shared_d == whatever)
    {
        // do something
    }
}
在上面的代码中,我可以在不使用互斥锁的情况下为哪些变量执行此操作?我的怀疑如下:

  • volatile bool
    :安全--无需互斥
  • volatile uint8\u t
    :安全--无需互斥
  • volatile uint16\u t
    :安全--无需互斥
  • volatile uint32\u t
    :安全--无需互斥
  • volatile uint64\u t
    :不安全--必须使用关键节或互斥锁
  • volatile float
    :安全--无需互斥
  • volatile double
    :不安全--必须使用关键部分或互斥锁 FreeRTOS的关键部分示例:
    -

    相关,但不回答我的问题:
  • (我自己关于8位AVR[和Arduino]微控制器原子性的问题和回答):

  • 取决于你所说的原子

    如果不是简单的加载或存储操作,如

    a += 1;
    
    那么,并非所有类型都是原子的

    如果是简单的存储或加载运算,32位、16位和8位数据类型是原子的。如果寄存器中的值必须标准化,则8和16位存储和加载可能不是原子的

    如果硬件支持位带,那么如果使用位带,则支持位带的内存区域中的位操作(设置和重置)是原子的

    注意。
    如果您的代码不允许未对齐操作,则8位和16位操作可能不是原子操作。

    有关此问题的最终确定答案,请直接跳到下面标题为“我的问题的最终答案”的部分

    2018年10月30日更新:我无意中引用了(稍微)错误的文档(但上面说的是完全相同的事情),所以我在这里的回答中修复了它们。有关详细信息,请参阅本答案底部的“2018年10月30日变更注释”

    我肯定不理解这里的每一个字,但是ARM v7-M架构参考手册(;)(不是技术参考手册[TRM],因为它没有讨论原子性)验证了我的假设:

    所以…我认为我问题底部的7个假设都是正确的。[2018年10月30日:是的,这是正确的。详情见下文。]


    2018年10月29日更新:

    还有一个小道消息: FreeRTOS创始人、专家和核心开发人员Richard Barry在
    tasks.c
    中指出

    /*由于变量的类型为BaseType\u t,因此不需要临界段*/

    …在STM32上读取“无符号长”(4字节)易失性变量时这意味着,他至少100%确定4字节读写在STM32上是原子的。他没有提到较小的字节读,但对于4字节读,他完全肯定。我必须假设4字节变量是本机处理器的宽度,而且,这对于实现这一点至关重要

    例如,在FreeRTOS v9.0.0的
    tasks.c
    中,第2173-2178行:

    UBaseType_t uxTaskGetNumberOfTasks( void )
    {
        /* A critical section is not required because the variables are of type
        BaseType_t. */
        return uxCurrentNumberOfTasks;
    }
    
    他用的正是这个短语

    /*由于变量的类型为BaseType\u t,因此不需要临界段*/

    …位于此文件中的两个不同位置

    我问题的最终答案:所有类型的原子“算术”都可以由CPU核心寄存器处理

    它可以是任何类型,一个或四个字节取决于体系结构和指令集

    但是修改内存中的任何变量至少需要3个系统步骤:RMW=读取内存以注册、修改寄存器和将寄存器写入内存。

    所以,只有当您控制CPU寄存器的使用时,原子修改才有可能,这意味着需要使用纯汇编程序,而不使用C或Cpp编译器

    当您使用C\Cpp编译器时,它会将全局或全局静态变量放在内存中,因此C\Cpp不会提供任何原子操作和类型


    注:例如,您可以使用“FPU寄存器”进行原子修改(如果您确实需要),但您必须对编译器和RTO隐藏该体系结构具有FPU。

    这将是特定芯片的ARM指令集手册的目的?可能的副本您必须查看汇编代码。您是否试图防御在相同数据上运行的两个内核,或者在一个写的中间被打断以在同一个内核上的另一个线程?后者:“在一个写的中间被打断,以达到同一个内核上的另一个线程”。谢谢你的回答。请查看mu更新的问题,并查看是否可以更明确地验证我的怀疑。顺便说一句,
    a+=1
    是两个操作,不是原子操作。同意。几年前,我在一个8位AVR处理器上通过增加(不是原子操作)一个本来具有原子读写能力的8位变量,艰难地学会了这一点。@zneak no,只有当操作是RMW时,否则它是原子的。它可能不是一致的(缓存),而是原子的。如果该操作是原子的,则多个内核同时尝试该操作将成功。事实并非如此,如果在一个循环中有两个内核这样做,那么肯定会损失一些增量
    UBaseType_t uxTaskGetNumberOfTasks( void )
    {
        /* A critical section is not required because the variables are of type
        BaseType_t. */
        return uxCurrentNumberOfTasks;
    }