Информация об изменениях

Сообщение Re[74]: Non-blocking io от 25.01.2019 13:19

Изменено 25.01.2019 13:21 vdimas

Re[74]: Non-blocking io
Здравствуйте, netch80, Вы писали:

V>>Английским по-белому написано, что если ты установил буфер сокета в нулевой размер, то важно порождать более одной асинхронной перекрывающейся операции.

V>>ИМХО, и без доки это должен подсказывать обычный здравый смысл, не?
N>Ты отвечаешь на другой вопрос, не о смысле overlapped.

ХЗ, может быть.
Я когда впервые более-менее всерьёз на это смотрел в начале 2000-х, понял именно так, что можно посылать перекрывающиеся запросы к одному хендлу.
Например, тогда IOCP еще не было популярным на клиенте, прямо по доке на клиентской стороне рекомендовалось использовать completion routines, т.е. в APC-очередь потока, из которого инициируется асинхронная операция, пихались колбэки от завершённых overlapped-операций. Там тоже докой гарантируется очередность прихода колбэков в случае нескольких одновременных запросов к одному хендлу.

Кстате, до середины 2000-х дотнетный асинхронный сокетный ввод/вывод работал поверх completion routines в текущем контексте синхронизации, это уже потом переписали на completion ports + пул потоков.


N>Всё равно не понял. Ладно, не так важно сейчас, подумаю на совсем досуге.


А чего там понимать?
К сокету обычно привязана некая структура/объект через поле epoll_event::data.
Эту структуру ты выделил из памяти динамически или расположил в поле другого объекта.
Цикл опроса сокетов за раз выгребает энное кол-во экземпляров epoll_event, берёт поле data, преобразует к известному типу (свой тип у каждой такой библиотеки или в низкоуровневом аналогичном самописном коде), затем у этой структуры берёт адрес колбэка, берет из неё же параметр void * user_data и вызывает этот колбэк с параметрами epoll_event::events и user_data. Ну или вызывает виртуальный метод объекта, если такая структура является ООП объектом, в этом случае user_data не нужен.

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

В общем, такая обвязка должна гарантировать, что вызванный колбэк не будет дёргать уже удалённую память.
Тут каждый извращается как может.
Подход Boost.Asio мне не кажется самым эффективным, зато он достаточно "дебелый" для большинства сценариев, т.е. способов совершить ошибку меньше.
Но зато в каких-нить своих "вылизанных" фреймворках можно сделать чуть эффективнее, но тогда "обвязка" должна быть достаточно умной, чтобы уметь отслеживать жизненный цикл хендлов и связанных с ним объектов из произвольных взаимных сценариев, возникающих м/у потоками.
Re[74]: Non-blocking io
Здравствуйте, netch80, Вы писали:

V>>Английским по-белому написано, что если ты установил буфер сокета в нулевой размер, то важно порождать более одной асинхронной перекрывающейся операции.

V>>ИМХО, и без доки это должен подсказывать обычный здравый смысл, не?
N>Ты отвечаешь на другой вопрос, не о смысле overlapped.

ХЗ, может быть.
Я когда впервые более-менее всерьёз на это смотрел в начале 2000-х, понял именно так, что можно посылать перекрывающиеся запросы к одному хендлу.
Например, тогда IOCP еще не было популярным на клиенте, прямо по доке на клиентской стороне рекомендовалось использовать completion routines, т.е. в APC-очередь потока, из которого инициируется асинхронная операция, пихались колбэки от завершённых overlapped-операций. Там тоже докой гарантируется очередность прихода колбэков в случае нескольких одновременных запросов к одному хендлу.

Кстате, до середины 2000-х дотнетный асинхронный сокетный ввод/вывод работал поверх completion routines в текущем контексте синхронизации, это уже потом переписали на completion ports + пул потоков.


N>Всё равно не понял. Ладно, не так важно сейчас, подумаю на совсем досуге.


А чего там понимать?
К сокету обычно привязана некая структура/объект через поле epoll_event::data.
Эту структуру ты выделил из памяти динамически или расположил в поле другого объекта.
Цикл опроса сокетов за раз выгребает энное кол-во экземпляров epoll_event, берёт поле data, преобразует к указателю на известный тип (свой тип у каждой такой библиотеки или в низкоуровневом аналогичном самописном коде), затем у этой структуры берёт адрес колбэка, берет из неё же параметр void * user_data и вызывает этот колбэк с параметрами epoll_event::events и user_data. Ну или вызывает виртуальный метод объекта, если такая структура является ООП объектом, в этом случае user_data не нужен.

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

В общем, такая обвязка должна гарантировать, что вызванный колбэк не будет дёргать уже удалённую память.
Тут каждый извращается как может.
Подход Boost.Asio мне не кажется самым эффективным, зато он достаточно "дебелый" для большинства сценариев, т.е. способов совершить ошибку меньше.
Но зато в каких-нить своих "вылизанных" фреймворках можно сделать чуть эффективнее, но тогда "обвязка" должна быть достаточно умной, чтобы уметь отслеживать жизненный цикл хендлов и связанных с ним объектов из произвольных взаимных сценариев, возникающих м/у потоками.