Сбой TCP-сервера Asio при выгрузке DLL - PullRequest
0 голосов
/ 26 ноября 2018

Я использую автономную библиотеку Asio для размещения простого TCP-сервера.Код находится внутри динамической библиотеки, которая загружается хост-приложением, которое я не могу контролировать.

Библиотека предоставляет функции Open и Close, которые хост-приложение должно вызывать после загрузки /перед выгрузкой библиотеки.
В функции Open я запускаю asio::io_service в отдельном потоке:

// start accepting connections
server.accept();

// start the asio service in a new thread
serviceThread = std::make_unique<std::thread>([this]() {
    ioService.run();
});

В функции Close я останавливаю службу и присоединяюсь к потоку:

// stop the asio service
ioService.stop();
serviceThread->join();

Серверная функция accept реализована следующим образом:

void Server::accept() {
    acceptor.async_accept(socket, [this](std::error_code err) {
        if (!err) {
            std::lock_guard<std::mutex> lock(sessionsMutex);
            sessions.emplace_back(new Session(*this, ioService, std::move(socket)));
        }

        accept();
    });
}

Другие функции, вызываемые asio::io_service, реализованы аналогично, то есть привязка лямбда-функции this передается в функцию asio async.

Этот код прекрасно работает, когда хост-приложение вызывает Open и Close, как требуется.
Однако иногда хост-приложение не вызываетфункция Close перед выгрузкой библиотеки, приводящая к ошибке сегментации, вызванной неправильным чтением памяти:

Thread 14 Crashed:
0   com.                            0x0000000121f1b14b asio::detail::scheduler::post_immediate_completion(asio::detail::scheduler_operation*, bool) + 27 (scheduler.ipp:281)
1   com.                            0x0000000121f1f17c void asio::io_context::executor_type::post<asio::detail::work_dispatcher<myproject::Server::Session::write()::$_3>, std::__1::allocator<void> >(asio::detail::work_dispatcher<myproject::Server::Session::write()::$_3>&&, std::__1::allocator<void> const&) const + 124 (io_context.hpp:270)
2   com.                            0x0000000121f1f027 asio::async_result<std::__1::decay<myproject::Server::Session::write()::$_3>::type, void ()>::return_type asio::post<asio::io_context::executor_type, myproject::Server::Session::write()::$_3>(asio::io_context::executor_type const&, myproject::Server::Session::write()::$_3&&, std::__1::enable_if<is_executor<asio::io_context::executor_type>::value, void>::type*) + 87 (post.hpp:58)
3   com.                            0x0000000121f11cb2 asio::async_result<std::__1::decay<myproject::Server::Session::write()::$_3>::type, void ()>::return_type asio::post<asio::io_context, myproject::Server::Session::write()::$_3>(asio::io_context&, myproject::Server::Session::write()::$_3&&, std::__1::enable_if<is_convertible<asio::io_context&, asio::execution_context&>::value, void>::type*) + 50 (post.hpp:69)
[...]

Какие у меня варианты?Существует ли кросс-платформенный способ обнаружения выгрузки библиотеки (должен работать в macOS и Windows), который позволяет мне в любом случае выполнить очистку?
Могу ли я изменить использование Asio для решения этой проблемы?поведение?

1 Ответ

0 голосов
/ 26 ноября 2018

Лучше всего сохранять библиотеку загруженной до тех пор, пока выполняется ее код, например, LoadLibrary при запуске потока для увеличения счетчика ссылок и FreeLibraryAndExitThread, когда рабочий поток умирает.

Хост-приложение может быть настолько несчастным, насколько ему нравится, что библиотека не выгружалась при запросе .... но именно она нарушила правило, не вызывая Close().

И нет, в этом нет ничего даже кроссплатформенного.Но обработка динамических библиотек довольно специфична для ОС.Может быть, вы найдете кроссплатформенную оболочку для динамической обработки библиотеки, в частности.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...