допустим 8 потоков.
2) Контекст asio::io_context my_context.
3) Сокет asio::ip::tcp::socket my_sock(my_context).
На первой половине потоков [0-3] выполняется run() у общего my_context.
На второй половине потоков [4-7] выполняется другой код.
Подскажите, пожалуста, насколько безопасно вызывать метод my_sock.close(ec) в следующих случаях:
1) Из кода, который выполняется внутри my_context (потоки [0-3])?
2) Из кода, который выполняется на других потоках [4-7]?
В обоих случаях гарантируется, что переменная my_sock валидна, деструктор у нее не вызывается, метод close() будет вызывать только один поток без конкуренции, но в сокете my_sock в это время может быть любая активность по сети и коллбекам.
И есть аналогичный вопрос для таймеров basic_waitable_timer, только вместо close вызываться будет cancel.
Документацию я читаю, и этот момент с гарантиями понять не могу...
Где-то я туплю, но вот где именно... 🙁
А вот откуда поток который хочет сказать close знает о сокете для начала?
Например, коллбек таймера таймаута «кранты» вызвался в другом потоке. А раз сработал таймер уровня «кранты», то единственная имеющая смысл операция для сокета - закрыть/оборвать сокет. Вопрос - как это сделать безопасно. Вероятность того, что на той стороне кто-то еще ждет, мала так что EOF от shutdown может не дойти и с точки зрения самих сокетов я бы в этом случае вызывал именно close(). (на случай, если вдруг что-то еще с той стороны прилетит, чтобы порт сразу не переиспользовался).
Есть наверное какой-то враппер, типа сессии. Сам то хэндл можно закрыть откуда угодно (и при этом всякие read/write прервутся). Но тут опасно то что останется сессия и её read/write cb с невалидным хэндлом. Это опасно, он может быть уже переиспользован. Надо на сессии все операции (включая таймеры) пускать через strand.
Невалидность сокета в любом случае не важна, так как асинхронные операции завершатся по asio::error::operation_aborted - это документировано. А дальше их не перезапускать - это уже ответственность кода сессии (она то знает, что случился таймаут кранты). Деструктор сокета в моем случе тоже не вызовается параллельно в close. strand - это хорошо, но это лишние мьютексты на пути, где всео перации кроме cancel таймера - последовательны.
Strand это не то чтобы мьютексы... Это очередь внутри очереди.
Нет, всё равно strand нужен. Вы больше получите неприятностей при параллельно выполняющихся dradline/read callback.
Которая не локфри, а защищается мьютексами.
Обсуждают сегодня