gpt4 book ai didi

c - 演示在信号处理过程中不使用volatile关键字时编译器的优化效果?

转载 作者:太空狗 更新时间:2023-10-29 17:12:15 28 4
gpt4 key购买 nike

在下面的代码中,我没有让变量quitvolatile sig_atomic_t。我将其保留为普通 int

#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>

#define UNUSED(x) (void) (x)

int quit;

void sigusr1_handler(int sig)
{
UNUSED(sig);
write(1, "handler\n", 8);
quit = 1;
}

int main()
{
struct sigaction sa;

sa.sa_handler = sigusr1_handler;
sa.sa_flags = 0;
sigemptyset(&sa.sa_mask);

if (sigaction(SIGUSR1, &sa, NULL) == -1) {
perror("sigaction");
return 1;
}

quit = 0;
while (!quit) {
printf("Working ...\n");
sleep(1);
}

printf("Exiting ...\n");
return 0;
}

由于 quit 变量未指定为 volatile,我期望编译器的优化器会优化代码中的 while 循环到:

    while (1) {
printf("Working ...\n");
sleep(1);
}

但我没有看到这种情况发生。在一个终端上,我运行以下命令。

$ gcc -O3 foo.c && ./a.out 
Working ...
Working ...

在另一个终端上,我将 SIGUSR1 发送到我的程序。

$ pkill -USR1 a.out

在第一个终端上,输出显示程序的信号处理程序被调用并且 while 循环退出。

Working ...
Working ...
handler
Exiting ...
$

由于 quit 不是 volatile,我如何演示循环的优化?

最佳答案

强制编译器从 while 条件中优化 quit 的负载可能很困难。我能够通过删除 while 循环的主体来做到这一点:

#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>

#define UNUSED(x) (void) (x)

int quit;

void sigusr1_handler(int sig)
{
UNUSED(sig);
write(1, "handler\n", 8);
quit = 1;
}

int main()
{
struct sigaction sa;

sa.sa_handler = sigusr1_handler;
sa.sa_flags = 0;
sigemptyset(&sa.sa_mask);

if (sigaction(SIGUSR1, &sa, NULL) == -1) {
perror("sigaction");
return 1;
}

quit = 0;
while (!quit) {
//printf("Working ...\n");
//sleep(1);
}

printf("Exiting ...\n");
return 0;
}

在 gcc 5.4 版上使用 -O3 编译 x86-64 时,这会导致无限循环,不检查 quit 变量。注意 .L5 处的跳转到自身:

.LC0:
.string "handler\n"
sigusr1_handler(int):
sub rsp, 8
mov edx, 8
mov esi, OFFSET FLAT:.LC0
mov edi, 1
call write
mov DWORD PTR quit[rip], 1
add rsp, 8
ret
.LC2:
.string "sigaction"
main:
sub rsp, 168
lea rdi, [rsp+8]
mov QWORD PTR [rsp], OFFSET FLAT:sigusr1_handler(int)
mov DWORD PTR [rsp+136], 0
call sigemptyset
xor edx, edx
mov rsi, rsp
mov edi, 10
call sigaction
cmp eax, -1
je .L7
mov DWORD PTR quit[rip], 0
.L5:
jmp .L5
.L7:
mov edi, OFFSET FLAT:.LC2
call perror
mov eax, 1
add rsp, 168
ret
quit:
.zero 4

将定义更改为 volatile int quit; 会导致正确的行为。请参阅 .L6 中的 movtestje 指令:

.LC0:
.string "handler\n"
sigusr1_handler(int):
sub rsp, 8
mov edx, 8
mov esi, OFFSET FLAT:.LC0
mov edi, 1
call write
mov DWORD PTR quit[rip], 1
add rsp, 8
ret
.LC2:
.string "sigaction"
.LC3:
.string "Exiting ..."
main:
sub rsp, 168
lea rdi, [rsp+8]
mov QWORD PTR [rsp], OFFSET FLAT:sigusr1_handler(int)
mov DWORD PTR [rsp+136], 0
call sigemptyset
xor edx, edx
mov rsi, rsp
mov edi, 10
call sigaction
cmp eax, -1
je .L11
mov DWORD PTR quit[rip], 0
.L6:
mov eax, DWORD PTR quit[rip]
test eax, eax
je .L6
mov edi, OFFSET FLAT:.LC3
call puts
xor eax, eax
.L5:
add rsp, 168
ret
.L11:
mov edi, OFFSET FLAT:.LC2
call perror
mov eax, 1
jmp .L5
quit:
.zero 4

你可以在这里玩两个例子:without volatilewith volatile .

关于c - 演示在信号处理过程中不使用volatile关键字时编译器的优化效果?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40456905/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com