Вопрос

Я хочу убедиться, что мое понимание верно.Такого рода вещи очень сложны, поэтому я почти уверен, что мне чего-то не хватает.У меня есть программа, состоящая из потока реального времени и потока, отличного от потока реального времени.Я хочу, чтобы поток, отличный от RT, мог менять местами указатель на память, которая используется потоком RT.

Из документов я понимаю, что это может быть достигнуто с помощью g++ с:

// global
Data *rt_data;

Data *swap_data(Data *new_data)
{
#ifdef __GNUC__
    // Atomic pointer swap.
    Data *old_d = __sync_lock_test_and_set(&rt_data, new_data);
#else
    // Non-atomic, cross your fingers.                                          
    Data *old_d = rt_data;
    rt_data = new_data;
#endif
    return old_d;
}

Это единственное место в программе (кроме начальной настройки), где rt_data модифицируется.Когда rt_data используется в контексте реального времени, копируется в локальный указатель.Для old_d, позже, когда будет уверена, что старая память не используется, она будет освобождена в потоке, отличном от RT.Правильно ли это?Нужен ли мне volatile куда угодно?Существуют ли другие примитивы синхронизации, которые я должен вызывать?

Кстати, я делаю это на C ++, хотя меня интересует, отличается ли ответ для C.

Заранее благодарю.

Это было полезно?

Решение

Обычно не используйте volatile при написании параллельного кода в C/C++.Семантика volatile настолько близки к тому, что вы хотите, что это заманчиво, но, в конце концов, нестабильно недостаточно.К сожалению Java/C# volatile != C/C++ volatile.У Херба Саттера отличный статья объясняя этот запутанный беспорядок.

Что вам действительно нужно, так это забор памяти. __sync_lock_test_and_set предоставляет вам ограждение.

Вам также понадобится ограничение памяти, когда вы копируете (загружаете) указатель rt_data в свою локальную копию.

Программирование без блокировки — сложная задача.Если вы хотите использовать расширения C++0x Gcc, это немного проще:

#include <cstdatomic>

std::atomic<Data*> rt_data;

Data* swap_data( Data* new_data )
{
   Data* old_data = rt_data.exchange(new_data);
   assert( old_data != new_data );
   return old_data;
}

void use_data( )
{
   Data* local = rt_data.load();
   /* ... */
}

Другие советы

Обновить:Этот ответ неверен, так как я упускаю из виду тот факт, что volatile гарантирует, что доступ к volatile переменные не переупорядочиваются, но не дают таких гарантий в отношении других неупорядоченных переменных.-volatile доступы и манипуляции.Защита памяти действительно обеспечивает такие гарантии и необходима для данного приложения.Мой первоначальный ответ приведен ниже, но не действуйте в соответствии с ним.Видишь этот ответ за хорошее объяснение в дыре в моем понимании, которое привело к следующему неправильному ответу.

Оригинальный ответ:

Да, вам нужно volatile на вашем rt_data декларация; каждый раз, когда переменная может быть изменена вне потока управления потока, обращающегося к ней, она должна быть объявлена volatile.В то время как вы, возможно, сможете уйти без volatile поскольку вы копируете на локальный указатель, volatile по крайней мере, помогает с документацией, а также препятствует некоторым оптимизациям компилятора, которые могут вызвать проблемы.Рассмотрим следующий пример, взятый из DDJ:

volatile int a;
int b;
a = 1;
b = a;

Если это возможно для a чтобы его значение менялось между a=1 и b=a, тогда a должно быть объявлено volatile (если, конечно, не присваивать устаревшее значение b является приемлемым).Многопоточность, особенно с атомарными примитивами, представляет собой такую ситуацию.Ситуация также запускается с переменными, измененными обработчиками сигналов, и переменными, сопоставленными нечетным ячейкам памяти (например,аппаратные регистры ввода-вывода).Смотрите также этот вопрос.

В остальном, по-моему, все в порядке.

В C я бы, вероятно, использовал атомарные примитивы, предоставленные Бойкий для этого.Они будут использовать атомарную операцию там, где это возможно, и вернутся к медленной, но правильной реализации на основе мьютекса, если атомарные операции недоступны.Boost может предоставить нечто подобное для C ++.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top