Везде, где я читаю, я вижу строгие рекомендации не использовать расслабленный порядок памяти, мне интересно, является ли следующий фрагмент кода одним из этих исключений, в которых это сработает, или есть какие-то разветвления, которых я не вижу.
class SessionHolder {
public:
void set_session(std::shared_ptr<Session> session) {
std::atomic_store_explicit(&_session, session, std::memory_order_relaxed);
}
std::shared_ptr<Session> get_session() const {
return std::atomic_load_explicit(&_session, std::memory_order_relaxed);
}
private:
std::shared_ptr<Session> _session;
};
В принципе, когда я использую get_session
, мне все равно, какой сеанс я получаю, если это сеанс или nullptr. Но если другой поток выполняет сохранение (что случается редко), я хотел бы в конечном итоге получить это значение с разумной задержкой.
memory_order_release
выкладывал бы изменения в другую ветку?Подробнее о том, как используется этот класс:
По сути, у меня есть какой-то поток, который непрерывно производит данные. В определенный момент клиентский процесс может подключиться (начать сеанс) и начать прослушивание этих данных. Поток-производитель непрерывно записывает в поток, если нет активного сеанса, данные отбрасываются, в противном случае отправляются клиенту. Другой поток в определенный момент (не часто), когда клиент подключается, достигает этого потока и устанавливает сеанс.
Поток-производитель должен иметь как можно меньше конфликтов, даже если это означает пропуск нескольких сообщений.
IMHO Меня учили, что memory_order_release действует только в сочетании с операцией memory_order_aquire (которой нет), так что разве это не бесполезно?
As I understand, it is not even guaranteed that I would get that value, just that I will get a value that was stored there at some point in time, but I could always get nullptr.
Да, гипотетически возможно, что каждый вызов get_session
будет возвращать нулевой указатель, но маловероятно. Одна гарантия того, что даже ослабленный порядок памяти предлагает, состоит в том, что, как только конкретный поток наблюдает значение, тот же поток не может впоследствии наблюдать предыдущее значение. Таким образом, как только конкретный поток начинает наблюдать ненулевой указатель, этот поток всегда будет наблюдать ненулевой указатель при последующих вызовах get_session
(при условии, что нулевой указатель никогда не сохраняется).
In practice seems to work, can I expect it to fail (always retrieving nullptr) in some situations/platform specifically?
Не то, чтобы я в курсе.
Can I adjust the memory order in the store operation only to fix this? e.g.
memory_order_release
would spread the changes to the other thread?
Нет. Стандарт не предоставляет никаких методов, гарантирующих, что межпотоковая связь будет завершена в течение определенного промежутка времени. Только реализация может дать такую гарантию.
И последнее замечание: nullptr
- это не то же самое, что «нулевой указатель». Это специальная константа уникального типа, которая может быть преобразована в нулевой указатель другого типа.
«тот же поток не может впоследствии наблюдать предыдущее значение» обратите внимание, что это не похоже на энергонезависимые ссылки на Java, которые могут дать сбой при оптимизации компилятора (если разные чтения оптимизированы по-разному)
Это только мое мнение: да, это отлично, и ваш анализ верен.