Безопасно ли перемещать данные между потоками, используя блокировку меньше очереди указателей

Вопрос:

Я readerwriterqueue простой круговой буфер для перемещения данных между потоками, используя (замечательно) Camerons readerwriterqueue чтобы предотвратить (де) распределения в моем приложении. Код выглядит примерно так:

using ElemPtr = std::unique_ptr<int>;
moodycamel::ReaderWriterQueue<ElemPtr> emptyQueue(10);
moodycamel::ReaderWriterQueue<ElemPtr> dataQueue(10);
LoadQueueWithPointers(emptyQueue);

//If statements removed for brevity
auto producer = [&]() {
ElemPtr ptr;
while (true) {
emptyQueue.try_dequeue(ptr);
LoadData(ptr);
dataQueue.try_enqueue(std::move(ptr));
}
};

//If statements removed for brevity
auto consumer = [&]() {
ElemPtr ptr;
while (true) {
dataQueue.try_dequeue(ptr);
ProcessData(ptr);
emptyQueue.try_enqueue(std::move(ptr));
}
};

std::thread producerThread(producer);
std::thread consumerThread(consumer);

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

Таким образом, мой вопрос: до сих пор мне повезло, и есть проблема с повреждением данных, которая ждет, чтобы произойти ИЛИ сделать забор памяти (std::memory_order_acquire, std::memory_order_release), используемой moodycamel::ReaderWriterQueue также защищает мои (не -атомные) операции памяти?

Лучший ответ:

TL; DR: Пока реализация ReaderWriterQueue<> использует атомные типы с правильными ReaderWriterQueue<> памяти, вы в порядке.

memory_order_release памяти, которые вам нужны, — memory_order_release на стороне писателя и memory_order_acquire со стороны читателя. Эти порядки памяти подразумевают, что все записи до того, как атомарная запись должна произойти сначала, и что все читается после того, как атомное чтение должно произойти позже. Эти другие записи/чтения включают ваши обращения к данным, расположенным за вашим ElemPtr.

Поскольку сама очередь должна отправлять данные из одного потока в другой, для того, чтобы отправлять указатели данных полезной нагрузки, необходимо использовать одинаковые порядки памяти на своих атомных метаданных. Таким образом, вы должны быть в безопасности, если ReaderWriterQueue<> реализован правильно.

Оцените статью
TechArks.Ru
Добавить комментарий