Gcc 优化条件

Gcc optimizes condition

我有以下代码:

#include <stdio.h>
#include <unistd.h>
#include <pthread.h>

char condA = 0;
volatile int vA = 0;
volatile int vB = 0;
void* thread_a(void* arg) {
    while (1) {
        if (1 == condA) {
            vA += 1;
            usleep(100);
        } else {
            ;
//          vB += 1;
//          usleep(100);
        }
    }
    return NULL;
}

void* thread_b(void* arg) {
    condA = 1;
    return NULL;
}

int main(void) {

    pthread_t threadA;
    pthread_t threadB;

    if (0 != pthread_create(&threadA, NULL, thread_a, NULL)) {
        return -2;
    }
    sleep(1);

    if (0 != pthread_create(&threadB, NULL, thread_b, NULL)) {
        return -1;
    }
    pthread_join(threadB, NULL);
    sleep(1);
    pthread_cancel(threadA);

    printf("value A is %d\n", vA);
    printf("value B is %d\n", vB);
    return 0;
}

我 运行 我的 gcc 5.4.0 带有 -O0 和 -O1。

在 O0 上,输出为:值 A 为 501

在O1上,输出为:值A为0

我知道将 condA 设置为 volatile 可以解决这个问题,但为什么会这样?明明是在另一个线程设置的条件,为什么编译器还要优化?

此外,如果我取消注释 else 语句中的代码,它会按预期工作。

我找到的部分答案:https://gcc.gnu.org/onlinedocs/gcc-5.4.0/gcc/Volatiles.html#Volatiles "C has the concept of volatile objects. These are normally accessed by pointers and used for accessing hardware or inter-thread communication.[...]"

但这并不能解释一个事实,即如果我取消注释 else 语句中的代码,程序将使用 -O1。

可变的变量不在您的代码中

char condA = 0;

所以线程永远不会从内存中读取它来检查是否满足条件

.L3:
  cmp al, 1
  jne .L3

如果您添加 volatile 关键字,代码会更改为正确的代码

.L8:
        movzx   eax, BYTE PTR condA[rip]
        cmp     al, 1
        jne     .L8

gcc 处理 volatile 正确。但是 volatile 不保证任何其他东西,尤其是没有原子性和一致性。

https://godbolt.org/z/dDTUz-


编辑

第二个问题2的答案很简单。

编译器看不到在程序执行时可以更改此标志的 ant 方式(因为没有直接调用线程函数)。线程中也不调用任何函数(因为它们可能容易产生副作用)。因此编译器优化了不需要的存储读取并将值保留在寄存器中。