c - 编译器如何知道不要将临界区内的代码移动到临界区外?

标签 c winapi

根据我的理解:

  • 编译器可以对我的代码进行任何它想要的重新排序。

  • 临界区内的代码不会被移到临界区外。

现在假设我有以下代码:

printf("Hi");

EnterCriticalSection(&CriticalSection);
printf("Inside the critical section");
printf("Also inside the critical section");
LeaveCriticalSection(&CriticalSection);

printf("Bye");

现在,编译器会实际查找函数 EnterCriticalSection()LeaveCriticalSection() 而不是将它们内部的代码移到外部吗?

最佳答案

A compiler can do whatever re-ordering it wants to my code.

这是不正确的。编译器是有限的。

The code inside a critical section will not be moved to the outside of the critical section.

这也是不正确的,具体取决于关键部分内部/外部的代码。

优化和约束

编译器对函数中的每一段代码都有一堆约束。这些约束可能是输入和输出(除非先执行 X,否则无法执行 Y)或更一般的语句,如“这会影响某处的内存内容”。编译器在编译您的代码时将保留这些约束。如果编译器不知道函数的作用,它将使用最严格的一组约束。

一般来说,这意味着编译器不会翻转两个函数调用的顺序1

f(); // Maybe affects memory somewhere.
g(); // Maybe affects memory somewhere.

这也意味着通常,如果您访问内存,这些内存访问必须相对于函数调用进行排序。

void myfunc(X *ptr) {
    my_lock(ptr->mutex);   // Maybe affects memory somewhere.
    ptr->field++;          // Definitely affects memory at ptr->field.
    my_unlock(ptr->mutex); // Maybe affects memory somewhere.
}

但是,它可以从关键部分重新排序:

int i = 5;
my_lock();   // Maybe affects memory somewhere.
i++;         // This is not "memory somewhere", this is my variable,
             // it's a register or on the stack and nobody else can
             // change it.
my_unlock(); // Maybe affects memory somewhere.

因此它可以将其重新排序为:

int i = 6;
my_lock();
my_unlock();

上面的代码可以重新排序,因为编译器对谁可以修改i有特殊的了解。如果你在其他地方有一些特殊的代码,它在堆栈中向上移动,试图创建一个指向 i 的指针,即使 &i 从未出现在你的程序中,你就是在违约与编译器(也就是你的程序有未定义的行为)。

我希望这能澄清一些事情。

脚注

1:您可以添加像 __declspec(noalias) 这样的注释来改变这个规则,LTO/whole-program-optimization/interprocedural optimization 也可以改变事情。

关于c - 编译器如何知道不要将临界区内的代码移动到临界区外?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42683527/

相关文章:

c - 如何创建 fscanf 格式字符串来接受空格和逗号 (,) 标记化

c - 为当前运行的线程重用 pthread_t 变量

c - 试图了解一个变量在这个小程序中从哪里获得它的值(value)

winapi - 如何使系统托盘(通知区域)图标接收 WM_MOUSEWHEEL 消息?

c++ - 在 Win32 C 中查询 Sqlite DB 的最佳方式

winapi - 如何将子窗口绑定(bind)到父窗口的相对位置?

c - E Balaguruswamy 书第 1 章主题子例程第 3 版中的 C 代码错误

c - fgets 读取特定大小

c++ - 如何使用数据字段获取组合框显示值?

language-agnostic - 您如何使用 Windows API 将信息写入 Windows "global (in-memory) variable"以供各种应用程序共享?