Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/cmake/2.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/wcf/4.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 此功能是否被视为重新进入?_C_Compiler Optimization_Reentrancy_Register Allocation - Fatal编程技术网

C 此功能是否被视为重新进入?

C 此功能是否被视为重新进入?,c,compiler-optimization,reentrancy,register-allocation,C,Compiler Optimization,Reentrancy,Register Allocation,我有一个具有以下实现的函数: void func (uint8 index, uint8 status) { if (status == 1) { myArrayOfStructures[index].status = 1; } else if (status == 0) { myArrayOfStructures[index].status = 0; } else { /* Nothing */ } } 注意:myArrayOf

我有一个具有以下实现的函数:

void func (uint8 index, uint8 status)
{
  if (status == 1)
  {
    myArrayOfStructures[index].status = 1;
  }

  else if (status == 0)
  {
    myArrayOfStructures[index].status = 0;
  }

  else
  {
    /* Nothing */
  }
}
注意:myArrayOfStructures是文件上的全局变量

由于以下分析,我认为只要通过堆栈传递其参数,该函数就是可重入函数:

函数调用时,函数的两个参数被推送到堆栈上。 如果函数本身从另一个OS任务中断,参数将第二次推送到堆栈上。 因此,函数的两个实例是“独立的”,因为每个实例在堆栈中都有自己的参数集

在此之前,我使用特定的编译器选项优化了此文件的速度

在优化之后,我发现这些参数的传递是通过寄存器完成的(我知道编译器有权做这样的事情(寄存器分配))。但这种优化使得该函数不可重入

所以,我的问题是

  • 上述功能是否真的是重新进入的
  • 如果是(重新进入),编译器如何进行这样的优化以恢复其重新进入状态
请让我参考你的答案


非常感谢。

无论编译器选择何种参数传递模式,您的函数都是可重入的

尽管依赖全局状态来正确执行会破坏重入性,但简单地访问全局状态并不一定会使函数不可重入。特别是,如果您从未读取全局变量,就像在函数中一样,那么代码是可重入的,因为它的执行不依赖于全局状态


就通过寄存器传递参数而言,上下文开关还保存所有寄存器的内容,因此无论参数传递模式如何,值都是中断安全的。

可能不是。我将指定它何时可重入,何时不可重入。但在此之前,您必须知道,尽管每个处理器只有一组物理寄存器,但这些寄存器的状态是每个线程。每个线程都保持其状态,不能篡改其他线程的寄存器状态。操作系统确保了这一点

一般来说,根据定义,编译器优化永远不会在正确的代码中引入错误。但是,优化可能会允许出现现有的bug,但是无论是否使用优化,bug都存在于代码中。因此,无论您编写什么代码,它都应该能够正确工作,而不考虑优化。这方面也有例外,但与问题无关

现在我来回答你的问题。假设函数已被调用,其中一些
索引
状态
为1。考虑以下情况:

void func (uint8 index, uint8 status)
{
  if (status == 1)
  {
    // Interrupt occurs here.
    myArrayOfStructures[index].status = 1;
  }

  else if (status == 0)
  {
    myArrayOfStructures[index].status = 0;
  }

  else
  {
    /* Nothing */
  }
}
当中断发生时,同一线程调用同一函数,且
索引和
状态均为0时,它会将该索引处数组元素的值设置为0。当第一次调用恢复时,它将向同一数组元素写入1。我假设你认为这是不正确的行为,因为新的状态丢失了。这表明函数是不可重入的

如果对数组元素的访问不是原子性的,那么即使在单词的单线程含义中,函数也是不可重入的,因为如果更新或读取数组元素,该线程可能会在中间中断

现在让我们考虑两个线程同时执行具有相同索引但具有不同状态的函数。在这种情况下,会发生数据竞争。这意味着两件事。首先,结果是不确定的。您不知道将存储哪个状态。如果这符合您的正确性要求,那么就可以了。但是,您可能希望存储最新状态,因此这种不确定性使其不可重入。其次,一个更大的问题是,根据C标准,单个数据竞争会使整个程序具有未定义的行为。这当然意味着函数是不可重入的

在没有缓存一致性的对称多处理器系统中或在分布式内存计算机系统中,同一数组元素可以有多个值,因此您将处于相同的情况,即最近的状态未知

编译器优化可以降低检测到错误的概率,从而使函数看起来是可重入的。例如,如果编译器可以确定只在
状态为0或1的情况下调用函数,那么它可以将生成的汇编代码优化为以下内容:

  • 比较状态和myArrayOfStructures[index]。状态是否相等

  • 有条件地将状态写入myArrayOfStructures[index]。如果 不平等

  • 这是有效的,因为全局变量初始化为零,因此数组中的每个元素都将是0或1。这段代码只对应于x86上的两条指令,其中使函数不可重入的情况较少


    事实上,编译器优化甚至可以使函数可重入。例如,如果编译器可以确定只在
    status
    为0的情况下调用函数,那么函数中的所有代码都将变为死代码,从而使其有效地可重入。这就是为什么我在开始时说“可能不会。”

    按寄存器传递或按堆栈传递根本不相关-每个操作系统任务都有自己的寄存器集(每个内核都有自己的寄存器,当切换到另一个任务/处理同一内核上的中断时,操作系统会根据需要保存和恢复它们)。旁注,但是该函数可以简化为一个简单的
    myArrayOfStructures[index]。status=!!地位。符合非零的
    C
    约定表示为真。通过使用
    stdbool.h
    instead@StoryTeller:不完全;sta