Почему GCC не распознает встроенные атомарные операции?

Как можно исправить ошибку "неопределённая ссылка на __atomic_compare_exchange_16" при компиляции программы с применением атомарных операций в GCC?
  • 24 апреля 2024 г. 6:00
Ответы на вопрос 2
GCC не распознает встроенные атомарные операции по умолчанию, так как они активируются только при наличии определенного количества аппаратного обеспечения. 

Для исправления ошибки "неопределённая ссылка на __atomic_compare_exchange_16" при компиляции программы с применением атомарных операций в GCC, необходимо убедиться, что используется поддерживаемая версия GCC (начиная с 4.7) и опции компилятора `-std=c11` или `-std=gnu11` для того, чтобы включить поддержку стандарта C11, который включает встроенные атомарные операции.

Например, для компиляции программы с использованием операции `__atomic_compare_exchange_16` в GCC можно использовать следующую команду:
```
gcc -std=gnu11 -o program program.c
```
Разобрался. 
Есть 2 замечания:
1. Поближе посмотрел на сигнатуру

bool __atomic_compare_exchange (type *ptr, type *expected, type *desired, bool weak, int success_memorder, int failure_memorder)


Короче говоря, мне нужно было передавать не указатели, а указатели на указатели. Исправил:

if (__atomic_compare_exchange(&l.head->next,  (struct entry**)NULL, &new_next, 1, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST))


Но потом начал ловить SEGFAULT. И тут пришел к 2 замечанию

2. Не заметил следующего в документации:

This built-in function implements an atomic compare and exchange operation. This compares the contents of *ptr with the contents of *expected. If equal, the operation is a read-modify-write operation that writes desired into *ptr. If they are not equal, the operation is a read and the current contents of *ptr are written into *expected. weak is true for weak compare_exchange, which may fail spuriously, and false for the strong variation, which never fails spuriously. Many targets only offer the strong variation and ignore the parameter. When in doubt, use the strong variation.


Т.е. если значение во 2 аргументе не равно значению из 1, то (!!!) по месту указателя 2 записывается полученное из указателя 1 значение. А у меня там был NULL (конец списка обозначается NULL). Заменил на корректно выделенный элемент списка и все заработало

int main(int argc, char const *argv[])
{
    struct list l;

    l.head = (struct entry *)malloc(sizeof(struct entry));
    l.head->next = NULL;
    l.head->value = 123;
    struct entry *old_next = (struct entry *)malloc(sizeof(struct entry));
    old_next->next = NULL;
    old_next->value = 555;
    l.head->next = old_next;

    struct entry *new_next = (struct entry *)malloc(sizeof(struct entry));
    new_next->value = 444;
    new_next->next = NULL;
    if (__atomic_compare_exchange(&l.head->next, &old_next, &new_next, 1, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST))
    {
        printf("ok\n");
        printf("success: next = %d\n", l.head->next->value);
    }
    else
    {
        printf("failed\n");
    }

    return 0;
}


Не хочу возиться со всякими dummy узлами, поэтому буду использовать __sync_bool_compare_and_swap
Похожие вопросы