G cc оптимизирует состояние - PullRequest
0 голосов
/ 28 января 2020

У меня есть следующий код:

#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;
}

Я запускаю свой g cc 5.4.0 с -O0 и -O1.

На O0 вывод: значение A равно 501

На O1 вывод: значение A равно 0

Я знаю, что установка condA на volatile исправит это, но почему это так? Почему компилятор оптимизирует условие, если оно явно задано в другом потоке?

Кроме того, если я раскомментирую код в операторе else, он будет работать, как и ожидалось.

Частичный ответ I найдено: https://gcc.gnu.org/onlinedocs/gcc-5.4.0/gcc/Volatiles.html#Volatiles "C имеет концепцию энергозависимых объектов. Обычно к ним обращаются указатели и они используются для доступа к аппаратным средствам или связи между потоками. [...]"

Но это не объясняет того факта, что если я раскомментирую код в операторе else, программа будет работать с -O1.

1 Ответ

0 голосов
/ 28 января 2020

переменная, которая имеет , чтобы быть энергозависимой, отсутствует в вашем коде

char condA = 0;

, поэтому поток никогда не считывает ее из памяти, чтобы проверить, выполнено ли условие

.L3:
  cmp al, 1
  jne .L3

если вы добавите ключевое слово volatile, код изменится на правильный

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

g cc обрабатывает volatile правильно. Но изменчивость не гарантирует ничего другого, особенно отсутствие атомарности и согласованности.

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


РЕДАКТИРОВАТЬ

Ответ на второй вопрос 2 довольно просто.

Компилятор не видит, каким образом этот флаг может быть изменен при выполнении программы (так как нет прямого вызова функции потока). В потоке также не вызываются функции (так как они могут быть побочными эффектами). Таким образом, компилятор оптимизирует чтение из хранилища как ненужное и сохраняет значение в регистре (ах).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...