Универсальный атомарный канал, который также будет работать с пользовательскими структурами

#c #generics #atomic

Вопрос:

Этот вопрос касается только stdatomic.h.

Скажем, мне нужен какой-то механизм, который позволяет мне создавать атомарные «каналы» с любыми данными, включая пользовательские struct . Я представляю себе что-то вроде:

 struct chan {
  atomic_intptr_t ptr;
};
 

Идея состоит в том, чтобы иметь _Atomic intptr_t возможность хранить ссылки буквально на любые данные.

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

 struct person {
  char * name;
};
 

…и я публикую это на своем атомном канале:

 struct person bob = {
    .name = "Bob"
};

struct person alice = {
    .name = "Alice"
};

struct chan c = {
    .ptr = amp;bob
};
 

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

 atomic_exchange(amp;c.ptr, amp;alice); 
 

Это работает, но gcc предупреждает меня:

предупреждение: инициализация ‘atomic_intptr_t’ {aka ‘long int’} из ‘struct person *’ делает целое число из указателя без приведения [-Wint-преобразование]

Поэтому мне кажется, что я выбрал неправильный подход.

Каков лучший способ иметь универсальный канал, способный атомарно обмениваться любыми данными? Можете _Generic ли вы помочь здесь?

Комментарии:

1. @selbie Я не занимаюсь C , если вы имеете в виду атомарный шаблон.

2. @SerejaBogolubov — Ой, ты прав. Моя вина!

Ответ №1:

Указатели также могут быть объявлены _Atomic , поэтому я думаю, что вам здесь нужно просто void * атомарное значение. (Возможно, вас вводит в заблуждение отсутствие удобного определения типа для этого, но оно отлично работает, и атомарные указатели не блокируются на большинстве распространенных платформ.) Таким образом:

 #include <stdatomic.h>
struct chan {
    void * _Atomic ptr;
} c;

struct person {
  char * name;
} alice;

int some_integer = 8;

void add_some_stuff(void) {
    atomic_exchange(amp;c.ptr, amp;alice);
    // ...
    atomic_exchange(amp;c.ptr, amp;some_integer);
    // ...
    atomic_exchange(amp;c.ptr, NULL);
}
 

Смотрите на godbolt

Комментарии:

1. Я не знал, что это работает и с необработанным указателем. Хотя в этом есть смысл. Спасибо!