Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
read_pos %= sizeof(buf);этот кусочек тоже должен быть атомарным, правильнее делать
Желательно также не забыть, что переменные, через которые мы обмениваемся данными между нитями, должны быть помечены как volatile, иначе компилятор запросто построит нам такую оптимизацию, которая легко сломает логику работы кода.Лишнее. Кэширование переменной не может пересекать барьер, которым является мьютекс, а если реализация вызываемой функции для компилятора непрозрачна, он не имеет права делать кэширование из-за возможности алиасинга.
Ещё совсем уж вскользь упомяну, что реализация SMP в процессорах Интел совершенно всепрощающа и гарантирует программисту, что все процессоры видят память одинаково, хотя и имеют раздельные кеши.Это не так. Процессоры могут видеть память по-разному, если не используется синхронизация.
Правда, останутся проблемы с read_pos %= sizeof(buf); — строго говоря, эту операцию нужно делать атомарно «внутри» atomic_add. То есть должна быть полная атомарная операция считывание-инкремент-ограничение.Можно так:
do
{
rpos = atomic_read(&read_pos);
} while (rpos != atomic_cmpxchg(&read_pos, rpos, (rpos + 1) % sizeof(buf));
ret = buf[rpos];
Вы предполагаете, что логика использования переменной обязательно пересекается с вызовами примитивов синхронизации, что необязательно.Можете привести пример? По мне, если без volatile не работает, это баг, который через перебдение предлагается замести под ковёр.
T *p;
rcu_read_lock();
T *lp = rcu_dereference(p);
<use lp>
<use lp again>
rcu_read_unlock();
Обзор примитивов синхронизации — Семафор и немного lockless-а