工具与软件:
我正在尝试创建一个内存范围以确保特定序列中、在代码中的特定点之前或之后写入某些参数。
我当前的解决方案是 asm ("NOP")。 我还发现使用 #pragma FUNC_CANNOT_INLINE 的函数调用用作屏障。 我想检查我是否可以依赖这些解决方案、是否有更好的解决方案、并了解编译器是否在将来的某个时候绕过我的解决方案并对我的代码重新排序。
我已经看到这个问题多次迭代、但实际上还没有 看到理想的分辨率。
我正在写入一个参数块、最后会设置一个标志。 中断将检查此标志、如果设置了该标志、则会处理这些参数并清除该标志。 必须在写入所有其他参数后设置该标志。 问题是、由于所有参数以及标志在编译器中看起来都相同、因此编译器会重新排列写入操作以提高效率、并将设置的标志移动到写入参数块过程中的某个位置。
我最初的实施发现了问题
// Original Implementation - issue
// non-interrupt
funct_config_params(new_param1, new_param2)
{
stored_param1 = new_param1;
stored_param2 = new_param2;
ready_to_load = true;
}
funct_interrupt()
{
if(ready_to_load)
{
runtime_param1 = stored param1;
runtime_param2 = stored param2;
ready_to_load = false;
}
}
我发现编译器可能会对写入进行重新排序、最终使用等效于此重新排序的汇编语言
// Original - Assembly equivalent
// non-interrupt
funct_config_params(new_param1, new_param2)
{
stored_param2 = new_param2;
ready_to_load = true; // OUT OF ORDER - MUST BE LAST
stored_param1 = new_param1;
}
这可能导致中断加载一个参数之前存储的值、以及另一个参数的新值。
// Current Implementation
// non-interrupt
funct_config_params(new_param1, new_param2)
{
stored_param1 = new_param1;
stored_param2 = new_param2;
asm("nop"); // seems to act as a memory fence
ready_to_load = true;
}
asm ("NOP")目前强制在汇编语言所要求的最后设定 READY_TO_LOAD 标志。
// Alertnate Solution
#pragma FUNC_CANNOT_INLINE
set_ready_to_load()
{
ready_to_load = true;
}
// non-interrupt
funct_config_params(new_param1, new_param2)
{
stored_param1 = new_param1;
stored_param2 = new_param2;
set_ready_to_load();
}
此使用#pragma FUNC_CANNOT_INLINE 的函数调用也通过强制函数调用来解决该问题。 函数调用似乎始终根据需要置于末尾。
在研究这个问题时、我发现了其他看起来不起作用的记忆棒:
asm ("");-此汇编块执行的任何操作似乎会立即得到优化、然后如果不将汇编用作块、编译器会重新排列语句。
asm volatile ("");-与 asm ("")相同;
asm volatile ("::" MEMORY ");-这似乎是建议使用 gcc 编译器执行内存围栏。 语法似乎完全不同、因此它不会生成、并且我尚未找到等效的语法。
因此、重申一下最初的问题、1)存储器障碍中是否 可靠并且不会被未来的编译器更改所击败、2)是否存在更好/更强大的 存储器障碍?