假设有如下所示的代码
void func1() // first way
{
CRITICALSECTIONTYPE CS;
ENTERCRITICALSECTION(CS);
int x = getValue();
LEAVECRITICALSECTION(CS);
}
void func2() // second way
{
int x;
CRITICALSECTIONTYPE CS;
ENTERCRITICALSECTION(CS);
x = getValue();
LEAVECRITICALSECTION(CS);
}
与第二种方式相比,第一种方式是否有任何(甚至是最轻微的)性能开销可能性?有什么特定的编译器优化它? 使用汇编代码首选答案。谢谢:))
答案 0 :(得分:2)
当然答案可能是编译器依赖的。
但是,我编写了一个程序,其中包含一个循环和一个在临界区创建的块变量。然后我通过在循环外创建变量来重新编译它。
我在你的问题上尝试了一些变化:
使用 初始化变量 ,编译器会生成其他初始化指令,您可以将其放入代码中,可能位于关键部分。
在自动存储中使用 未初始化的动态数组 (例如:char y[n];
),原则是相同的:不会有其他指令关键部分。为什么这样 ?因为标准只有在大小(此处为n
)不变时才接受这些动态数组。同样,在代码生成时,编译器知道在函数入口处在堆栈上分配了多少空间。
如果需要调用 构造函数 ,对于更复杂的对象,则必须在临界区中执行相应的指令。
无论如何,请记住,即使在临界区添加代码,优化器仍然可以找到优化它的方法(例如:常量传播,检测循环不变量等)。
<强> 修改 强>
根据您的要求,这里是第一个案例的ASM代码摘录。很抱歉这个大屏幕截图,但它是唯一能轻松显示代码比较的方法。差异以黄色和灰色突出显示。
您会注意到差异只是与C ++源相对应的注释,以及使用b的行(sollely,因为堆栈偏移被命名为_b$1
用于块变量和{{1}用于函数变量)。 (1)堆栈偏移以访问变量(2)函数中的入口点(3)局部变量初始化的示例(4)临界区中的变量(左侧变量在区域内部,右侧外部创建)。