Boost:: asio io_service пул потоков

Какое правильное использование настроек пула потоков для io_service? Эти 2 заявления из документации отбрасывают меня:

io_service:: run

Нормальный выход из функции run() означает, что объект io_service остановлен (функция stop() возвращает true). Последующие вызовы run(), run_one(), poll() или poll_one() будут немедленно возвращены, если не был предыдущий вызов reset().

io_service:: reset

Эта функция должна быть вызвана до любого второго или более позднего набора вызовов функций run(), run_one(), poll() или poll_one(), когда предыдущий вызов этих функций возвращался из-за остановки io_service или заканчивается работа.

Вот что я сейчас делаю:

boost::thread_group     m_Threads;
boost::asio::io_service m_IoService;
boost::barrier          m_Barrier(numThreads);

for( unsigned int i = 0; i < numThreads; ++i )
{
    m_Threads.create_thread(
        [&]()
        {
            for(;;)
            {
                m_IoService.run();

                if( m_Barrier.wait() )  //  will only return true for 1 thread
                {
                    m_IoService.reset();
                }
                m_Barrier.wait();
            }
        });
}

m_IoService.stop();
m_Threads.interrupt_all();
m_Threads.join_all();

Кажется, что все работает нормально, если я просто помещаю m_IoService.run() в бесконечный цикл (который, как представляется, указывает на документацию, не должно быть). Каков правильный путь?

Ответы

Ответ 1

run() является блокирующим вызовом и будет выполнять все события, которые он может перед возвратом. Он будет возвращаться только в том случае, если больше не будет обработано событий. Как только он вернется, вы должны вызывать reset() в io_service перед вызовом run() снова.

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

Если вы настроите work на io_service, он никогда не выйдет естественным путем, поэтому вам не нужно будет звонить reset().

work some_work(m_IoService); // this will keep the io_service live.

for( unsigned int i = 0; i < numThreads; ++i )
{
  m_Threads.create_thread(
    [&]()
    {
      m_IoService.run();
    });
}

Теперь все потоки отправляют события на io_service

// Now post your jobs
m_IoService.post(boost::bind(...)); // this will be executed in one of the threads
m_IoService.post(boost::bind(...)); // this will be executed in one of the threads
m_IoService.post(boost::bind(...)); // this will be executed in one of the threads

m_IoService.stop(); // explicitly stop the io_service
// now join all the threads and wait for them to exit