Здравствуйте, fdn721, Вы писали:
F>Здравствуйте, jazzer, Вы писали:
J>>проверить в этой "куче асинхронных операций" error::operation_aborted религия не позволяет?
F>Все такие умные, а если handler ещё выполняется во время close? Close ни чего не ждёт.
Что значит "handler ещё выполняется во время close"? Что один поток зовет close, пока в другом работает handler? Ну так защищать надо мьютексами, чтоб не было такого
Здравствуйте, kaa.python, Вы писали:
KP>Только в результате получится еще одно ASIO реализующее фантазии другого автора, только более глючное, так как в отладку вложить сопоставимые ресурсы будет трудно. Не нравится ASIO – возьми другую библиотеку по вкусу, благо альтернатив очень много.
Во первых, asio не глючное, во вторых, не факт что глючным будет своя реализация, и в третьих,
в своей реализации будут не отвлечённые фантазии, а воплощение именно того, что нужно в конкретном
приложении и ничего лишнего.
J>Что значит "handler ещё выполняется во время close"? Что один поток зовет close, пока в другом работает handler? Ну так защищать надо мьютексами, чтоб не было такого
Вот это я и называю костылями. Нужна насовать мютексов/флагов во все handler-ы только ради того, чтобы корректно закрыть соединение.
Здравствуйте, fdn721, Вы писали:
J>>Что значит "handler ещё выполняется во время close"? Что один поток зовет close, пока в другом работает handler? Ну так защищать надо мьютексами, чтоб не было такого
F>Вот это я и называю костылями. Нужна насовать мютексов/флагов во все handler-ы только ради того, чтобы корректно закрыть соединение.
Эти "костыли" нужны всегда, когда у тебя объекты шарятся между потоками, и asio тут вообще ни при чем.
Здравствуйте, jazzer, Вы писали:
J>Эти "костыли" нужны всегда, когда у тебя объекты шарятся между потоками, и asio тут вообще ни при чем.
претензия fdn721 состоит в том, что asio не предлагает средств для уменьшения сложности написания программ с асинхр вводом\выводом (более конкретно, проблема завершения приложения и отмены асинхр операций, отслеживание времени жизни объектов). как следствие имеем хрупкий код, нестабильность, падения
именно asio должен был что-то предложить.
как вариант, сигнатура функции асинхронных операций должна не только принимать континуацию, но и выдавать хендл для управления запущенной операцией. это практикуется в том же C#: https://msdn.microsoft.com/en-us/library/dd321424(v=vs.110).aspx https://msdn.microsoft.com/en-us/library/hh191443(v=vs.110).aspx
Здравствуйте, uzhas, Вы писали:
J>>Эти "костыли" нужны всегда, когда у тебя объекты шарятся между потоками, и asio тут вообще ни при чем. U>претензия ТС состоит в том, что asio не предлагает средств для уменьшения сложности написания программ с асинхр вводом\выводом
Здравствуйте, PM, Вы писали:
PM>Здравствуйте, fdn721, Вы писали:
F>>А как? Ну вот к примеру стандартная ситуация: PM>[здесь был код] F>>Как с этим бороться без кучи костылей???
PM>Общепринятый подход показан в примерах к Boost.asio — положиться на подсчет ссылок в shared_ptr, передавать shared_ptr вместо this в асинхронные обработчики. Тогда при завершении последнего обработчика, объект будет удален.
а как в Read при таком подходе избавиться от зацикливания ?
( я в принципе знаю — но это тоже костыль )
во вторых — например на таймерах можно дождаться их завершения — не понимаю какая проблема сделать тоже самое на сокетах ... можно конечно свой condition воткнуть, но почему бы
не делать это силами библиотеки?
Здравствуйте, The Passenger, Вы писали:
PM>>Общепринятый подход показан в примерах к Boost.asio — положиться на подсчет ссылок в shared_ptr, передавать shared_ptr вместо this в асинхронные обработчики. Тогда при завершении последнего обработчика, объект будет удален.
Это не подход, а оторванные от жизни примеры. Объект(будем называть его соединение) само по себе не живет(если это не эхо сервер), оно всё равно связано с остальной программой. Так вот реализовать эту связь с соединением, у которого какое-то произвольное время жизни, проблематично. Кроме того этим соединением часто приходится управлять из вне(т.е. им кто-то владеет, посылает данные, получает ответы). Ну вот к примеру надо переустановить соединение, как это сделать корректно при таком подходе? Всё обрастёт кучей мютексов и week_ptr-ов. Если у тебя есть хорошее решение — поделись, я тебе буду благодарен.
Здравствуйте, fdn721, Вы писали:
F>Это не подход, а оторванные от жизни примеры. Объект(будем называть его соединение) само по себе не живет(если это не эхо сервер), оно всё равно связано с остальной программой. Так вот реализовать эту связь с соединением, у которого какое-то произвольное время жизни, проблематично. Кроме того этим соединением часто приходится управлять из вне(т.е. им кто-то владеет, посылает данные, получает ответы). Ну вот к примеру надо переустановить соединение, как это сделать корректно при таком подходе? Всё обрастёт кучей мютексов и week_ptr-ов.
Для каждого соединения создаётся объект с отдельным asio сокетом как полем объекта. Объект,
при создании, помещается в дерево, список или хеш. Асинхронные обработчики будут являться методами
этих объектов. Этот объект уничтожается если в асинхронный хендлер передаётся сообщение об ошибке,
или закрытии соединения, после чего объект сам себя уничтожает, в своём же методе, то есть в асинхронном
обработчике. Всё операции и хендлеры обработки результатов их выполнения, исполняются в одном потоке io_service.
Поток io_service сам выбирает asio сокет для которого нужно вызвать хендлер, а тот уже определяет "свой" объект,
так как в asio функции хендлер "передаётся с объектом"
и совершает действия с его полями, составляя состояние того или иного соединения.
При уничтожении всех соединений, можно пройтись по всему дереву/списку с его очищением. Если одного потока io_service
оказыватся мало, можно создать их любое количество, с отдельным деревом соединений на каждый.
S>Для каждого соединения создаётся объект с отдельным asio сокетом как полем объекта. Объект, S>при создании, помещается в дерево, список или хеш. Асинхронные обработчики будут являться методами S>этих объектов. Этот объект уничтожается если в асинхронный хендлер передаётся сообщение об ошибке, S>или закрытии соединения, после чего объект сам себя уничтожает, в своём же методе, то есть в асинхронном S>обработчике. Всё операции и хендлеры обработки результатов их выполнения, исполняются в одном потоке io_service. S>Поток io_service сам выбирает asio сокет для которого нужно вызвать хендлер, а тот уже определяет "свой" объект, S>так как в asio функции хендлер "передаётся с объектом"
Вы только что описали ручное управление жизнью объектов, для которого и предназначен shared_ptr. И про удаление в случае ошибки нужно не забыть в каждом асинхронном обработчике
Почему-то вы исходите из предпослыки, что обработчики asio выполняются в одном потоке. На самом деле можно (и нужно в Windows) запускать несколько потоков обработки на одном io_service. В этом случае, в вашем примере кода в serv::start() потребуется mutex, защищающий conn_mas, как и реализации функции del_conn()
Ну то есть в итоге придем к тому, что fdn721 назвал костылями.
Здравствуйте, The Passenger, Вы писали:
PM>>Общепринятый подход показан в примерах к Boost.asio — положиться на подсчет ссылок в shared_ptr, передавать shared_ptr вместо this в асинхронные обработчики. Тогда при завершении последнего обработчика, объект будет удален.
TP>а как в Read при таком подходе избавиться от зацикливания ? TP>( я в принципе знаю — но это тоже костыль )
Зацикливания чего, ссылок на объекты или обработчиков? Непонятный вопрос.
TP>во вторых — например на таймерах можно дождаться их завершения — не понимаю какая проблема сделать тоже самое на сокетах ... можно конечно свой condition воткнуть, но почему бы TP>не делать это силами библиотеки?
Я не автор, но могу предположить, потому что это непросто сделать кроссплатформенно.
Здравствуйте, fdn721, Вы писали:
F>Это не подход, а оторванные от жизни примеры. Объект(будем называть его соединение) само по себе не живет(если это не эхо сервер), оно всё равно связано с остальной программой. Так вот реализовать эту связь с соединением, у которого какое-то произвольное время жизни, проблематично.
Вот у меня, например, совсем не эхо сервер. И соединение прекрасно живёт себе в виде умного указателя в недрах io_service + у меня в списке. После того, как я для соединения делаю close и удаляю из своего списка соединений, как только asio завершит для него все асинхронные операции, связанные с закрытием сокета, оно прекрасно удаляется из недр io_service, после чего умный указатель вызывает деструктор объекта соединения. Это замечательно работает, избавляя меня от необходимости ручного управления памятью.
Здравствуйте, PM, Вы писали:
PM>Вы только что описали ручное управление жизнью объектов, для которого и предназначен shared_ptr. И про удаление в случае ошибки нужно не забыть в каждом асинхронном обработчике
Где только таких учат и откуда они вообще берутся? А голову они нигде не забывают? Этот хронические
жабисты пусть забывают, любой C++ ник должен уметь вручную управлять объектами, несмотря на обилие
ptr-ов, ибо пригодится, и вообще, ручное управление памятью есть одно из ключевых возможностей в C++,
доставшихся в наследство из Cи.
PM>Почему-то вы исходите из предпослыки, что обработчики asio выполняются в одном потоке. На самом деле можно (и нужно в Windows) запускать несколько потоков обработки на одном io_service. В этом случае, в вашем примере кода в serv::start() потребуется mutex, защищающий conn_mas, как и реализации функции del_conn()
А можно вообще без mutex-ов, и вообще без каких либо локов, просто распареллелив данные между потоками.
Здравствуйте, smeeld, Вы писали:
PM>>Вы только что описали ручное управление жизнью объектов, для которого и предназначен shared_ptr. И про удаление в случае ошибки нужно не забыть в каждом асинхронном обработчике
S>Где только таких учат и откуда они вообще берутся? А голову они нигде не забывают? Этот хронические S>жабисты пусть забывают, любой C++ ник должен уметь вручную управлять объектами, несмотря на обилие S>ptr-ов, ибо пригодится, и вообще, ручное управление памятью есть одно из ключевых возможностей в C++, S>доставшихся в наследство из Cи.
Жизнь таких учит, что в С++ коде внезапно бывают исключения, что люди ошибаются, что код меняется. Должен уметь != должен делать. Если вам незнакомо RAII и нравится писать в стиле С, так и пишите на С, пользуйтесь на здоровье goto cleanup.
PM>>Почему-то вы исходите из предпослыки, что обработчики asio выполняются в одном потоке. На самом деле можно (и нужно в Windows) запускать несколько потоков обработки на одном io_service. В этом случае, в вашем примере кода в serv::start() потребуется mutex, защищающий conn_mas, как и реализации функции del_conn()
S>А можно вообще без mutex-ов, и вообще без каких либо локов, просто распареллелив данные между потоками.
Можно многое, но если будет использоваться пул потоков для обработчиков асинхронных операций, без блокировок в каком-либо виде не обойтись.
Хотя, дискутировать с вами не собираюсь, тема была не про это. Ваша позиция ясна из предыдущих сообщений. Надеюсь, мне не придется с вами работать в одной команде, либо поддерживать ваш код.
Здравствуйте, fdn721, Вы писали:
F>Да видел я все эти примеры, только они все однотипные. Вся обработка идёт внутри этого самого "MyClient". Только я не эхо сервер/клиент пишу. А как только начинаешь взаимодействовать из MyClient с остальной частью программы вылезают все те же самые проблемы с кучей асинхронных операций, которые невозможно просто взять и завершить.
F>ЗЫ По началу кажется что ASIO это очень мощное решение, а по факты всегда всё сводится к одному подходу. Шаг влево, шаг в право и у тебя куча проблем.
Несколько лет назад смотрел код libtorrent, там использовалась asio.
Здравствуйте, PM, Вы писали:
PM>int main() PM>{ PM> ... PM> boost::shared_ptr<MyClient> client = boost::make_shared<MyClient>(); PM> client->Open(); PM> client->Close(); //<<---- Тут ASIO запланирует вызов HandleConnect со значением error::operation_aborted. PM>// delete client; //<<---- не нужно, объект будет удален, когда на него не останется ссылок PM> ... PM>}
Так тут точно такая же проблема: client будет удалён также после выхода из блока, что не гарантирует что все хендлеры завершаться до него.
Вообще сам подсчёт ссылок не решает проблем с удалением данных после завершения выполнения кода связанного с этими данными. А иногда делает даже хуже, т.к. ты не знаешь в какой момент объект разрушиться, нет вообще гарантий, что при написании какого-то кусочка кода объект в этот момент не будет жить или наоборот будет разрушен. Каждый раз при добавлении подобного кода приходится проходить мысленно по всей модели взаимодействий кода и данных. А это задалбывает.
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Здравствуйте, uzhas, Вы писали:
U>Здравствуйте, jazzer, Вы писали:
J>>Эти "костыли" нужны всегда, когда у тебя объекты шарятся между потоками, и asio тут вообще ни при чем.
U>претензия fdn721 состоит в том, что asio не предлагает средств для уменьшения сложности написания программ с асинхр вводом\выводом (более конкретно, проблема завершения приложения и отмены асинхр операций, отслеживание времени жизни объектов). как следствие имеем хрупкий код, нестабильность, падения U>именно asio должен был что-то предложить. U>как вариант, сигнатура функции асинхронных операций должна не только принимать континуацию, но и выдавать хендл для управления запущенной операцией.
Ну так тогда придется где-то хранить эти хэндлы, так что тот же гемор, вид сбоку
У fdn721 же добавление континуации и удаление сокета разнесены в коде, я так предполагаю (иначе можно было бы просто континуацию не создавать, если мы знаем, что тут же сокет прибьем)
Далее, зачем обязательно убивать сокет явно? Достаточно хранить его в любом умном указателе и передавать явно в континуацию. Тогда при закрытии сокета в континуацию придет operation_aborted — ты в результате просто не поставишь в очередь очередную континуацию (которая держала бы сокет на плаву), и сокет мирно помрет сам вместе с указателем.
ЗЫ Есть какой-нть нормальный перевод для continuation? Калька — это уродство какое-то "Продолжение" тоже плохо выглядит, так как имеет самостоятельный смысл. "Функция/процедура продолжения"?