Остановка io_service после завершения каждого потока - PullRequest
0 голосов
/ 28 апреля 2018

Я хотел бы заставить программу ждать, пока она не завершит все запущенные потоки, в отличие от ioService.stop();, который останавливает ioService без ожидания. Я попробовал следующий код, который работает нормально, но останавливает ioService, не дожидаясь окончания потоков.

#include <iostream>
#include <boost/asio/io_service.hpp>
#include <boost/bind.hpp>
#include <boost/thread/thread.hpp>


void myTask (std::string &str);

int main(int argc, char **argv){

    uint16_t total_threads = 4;

    /*
     * Create an asio::io_service and a thread_group
     */
    boost::asio::io_service ioService;
    boost::thread_group threadpool;    

    /*
     * This will start the ioService processing loop. 
     */     
    boost::asio::io_service::work work(ioService);

    /*
     * This will add threads to the thread pool.
     */
    for (std::size_t i = 0; i < total_threads; ++i)
        threadpool.create_thread(
                boost::bind(&boost::asio::io_service::run, &ioService));    

    /*
     * This will assign tasks to the thread pool.
     */
    std::string str = "Hello world";
    ioService.post(boost::bind(myTask, std::ref(str) ));



    ioService.stop();

    /*
     * thread pool are finished with
     * their assigned tasks and 'join' them.
     */
    threadpool.join_all();

    return 0;

}


void myTask (std::string &str){
    std::cout << str << std::endl;
}

Компилировать с: -lboost_serialization -lboost_thread -lboost_system

1 Ответ

0 голосов
/ 07 мая 2018

Ваша проблема в том, что вы создаете work как переменную в стеке. work сообщает io_service, что еще предстоит проделать работу. Из руководства:

Деструктор уведомляет io_service, что работа завершена.

Поскольку работа в main выполняется в стеке, срок ее службы больше, чем вы хотите. Он не будет разрушен до тех пор, пока главные выходы. Вместо этого создайте его в куче, чтобы вы могли явно уничтожить его. Измените его на:

using namespace boost::asio;
boost::scoped_ptr<io_service::work> work(new io_service::work(ioService));

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

work.reset();
threadpool.join_all();

Это вызовет ~work(), который удалит рабочий объект из io_service. Это, в свою очередь, приведет к выходу io_service::run после завершения последней ожидающей операции.

Еще несколько заметок:

  • Я бы не стал давать переменной то же имя, что и у ее класса. Я бы не стал писать io_service::work work(io_service); Это слишком запутанно. Я бы написал что-то вроде io_service::work some_work(io_service);
  • Будьте осторожны с io_service.post(... std::ref(str)); Вы передаете ссылку на действие post io_service. Переменная str должна жить достаточно долго для завершения задачи. Я уверен, что это здесь только для примера. В реальных приложениях может быть на удивление трудно гарантировать, что параметры, передаваемые рабочим объектам, не будут преждевременно разрушены. Я много использую shared_ptr<> или, в случаях, когда это невозможно, иногда подсчитываю количество ожидающих действий io_service с boost :: atomic
...