Используйте изменчивые данные с методами, не перегруженными для изменчивых данных

Я немного в конце своих знаний.

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

Мой сегмент общей памяти приведен к изменчивому указателю на структуру, и я могу работать с этим. Структура должна быть изменчивой, потому что мне иногда нужно вращаться до тех пор, пока не изменится какое-то значение в разделяемой памяти — поэтому использование volatile — не вариант.

Сейчас я использую внешнюю C ++ -библиотеку (SystemC, но здесь это не должно иметь значения), из которой моя структура содержит члены sc_time. Несмотря на то, что у меня есть доступ к источнику библиотеки, я не хочу зависеть от сделанных мной модификаций, вероятных поломок или попадания в ад.

Теперь этот класс «sc_time» имеет операторы для сравнения и присваивания. Эти операторы не работают с volatile sc_time — пока что неудивительно.

Теперь мой вопрос: есть ли способ отвратить эту изменчивость, не нарушая семантику? Я могу использовать часто упоминаемый const_cast<> или простой C-cast, но что тогда будет делать компилятор? Я мог бы, вероятно, даже просто memcpy () данных — но опять же, каков будет результат?

Любые предложения будут приветствоваться — у меня не возникло бы никаких проблем с использованием обертки только для C или любого другого метода — до тех пор, пока он работает ™, но моим последним средством будет некоторый небольшой подобный memcpy ассемблерный код для реального чтения данные — и это то, что я хотел бы избежать.

Спасибо за ваше время, читая это 🙂

Редактировать: добавлен небольшой фрагмент кода:

struct shared_memory{
sc_time time1;
sc_time time2;
sc_time time3;
...
}

...

class foo
{
foo();   // attach shared memory and assign to *mem
...
pthread_mutex_t mutex;
volatile struct shared_memory *mem;
...
void do_stuff();  // periodically called
};

void foo::do_stuff()
{
...
lock_mutex(mutex);
sc_time t1 = mem->time1;
sc_time t2 = mem->time2;
sc_time t3 = mem->time3;
unlock_mutex(mutex);
...
while(t1 < t2 || t1 < t3){
lock_mutex(mutex);
t1 = mem->time1;
t2 = mem->time2;
t3 = mem->time3;
unlock_mutex(mutex);
}

}

3

Решение

Если вам нужно вращаться в ожидании изменений переменной, вы не блокировка правильно. Ожидание вращения всегда должно предполагать атомарный доступ к данным. Речь идет не только о получении последней версии данных, но и о согласованности, например, данные могут быть разделены на несколько строк кэша, и вы можете просто получить младшие байты старой версии и старшие байты обновленной.

По этой причине новые стандарты C и C ++ имеют концепции и инструменты для атомарного доступа, используйте их, если хотите. Если у вас их нет, используйте расширение компилятора (или библиотеки): все современные процессоры имеют атомарные инструкции, а любой приличный компилятор имеет расширение, которое предоставляет такие функции.

Играть в игры с volatile это не путь, по которому ты должен идти. Если вы выбросили volatile и передать такой объект функции, которая не ожидает, что под ней что-то изменится, все может произойти. В частности, когда в библиотеке нет volatile составлены оптимизации, которые могут испортить ваши данные. Не делай этого.

Редактировать: Поскольку вы также пометили свой вопрос с помощью gcc, по уважительной причине они __sync_lock_test_and_set Встроенные со времени долгое время как расширение. Используй это. Возможно, для вашей конкретной комбинации архитектуры это разрешит точно такой же код, но, поверьте, ребята из gcc знают, когда им нужно добавить магию ассемблера, чтобы дать вам гарантии в отношении ваших данных.

2

Другие решения

Вы можете использовать const_cast, чтобы покончить с «volatile», а также с «const» переменных.

Примечание: переменная внутри функции будет рассматриваться компилятором как энергонезависимая 🙂

0

По вопросам рекламы [email protected]