Boost,在io_service.post之前创建线程池

Boost, create thread pool before io_service.post

本文关键字:创建 线程 post service io Boost      更新时间:2023-10-16

我成功地测试了一个关于boost io_service:的示例

for(x = 0; x < loops; x++)
{
    // Add work to ioService.
    for (i = 0; i < number_of_threads; i++)
    {   
        ioService.post(boost::bind(worker_task, data, pre_data[i]));
    }
    // Now that the ioService has work, use a pool of threads to service it.
    for (i = 0; i < number_of_threads; i++)
    {   
        threadpool.create_thread(boost::bind(
            &boost::asio::io_service::run, &ioService));      
    }
    // threads in the threadpool will be completed and can be joined.
    threadpool.join_all();
}

这将循环几次,并且需要一点时间,因为每次都为每个循环创建线程。

有没有一种方法可以创建所有需要的线程。然后在循环中发布每个线程的工作。工作完成后,需要等待,直到所有线程都完成了它们的工作!

类似这样的东西:

// start/create threads
for (i = 0; i < number_of_threads; i++)
{   
    threadpool.create_thread(boost::bind(
        &boost::asio::io_service::run, &ioService));      
}
for(x = 0; x < loops; x++)
{
    // Add work to ioService.
    for (i = 0; i < number_of_threads; i++)
    {   
        ioService.post(boost::bind(worker_task, data, pre_data[i]));
    }
    // threads in the threadpool will be completed and can be joined.
    threadpool.join_all();
}

这里的问题是,您的工作线程将在创建后立即完成,因为没有工作要做。io_service::run()将立即返回,因此,除非您设法在所有工作线程都有机会调用run()之前潜入其中一个post调用,否则它们都将立即完成。

解决此问题的两种方法:

  • 使用屏障阻止工人立即呼叫run()。只有在作品发布后才能解锁它们
  • 使用io_service::work对象来防止run返回。一旦发布了所有内容,就可以销毁工作对象(并且必须在尝试再次join工作者之前销毁)

循环并不是真正有用的。

这是一个更好的工作方式。我在回调中获取数据:

void worker_task(uint8_t * data, uint32_t len)
{
    uint32_t pos = 0;
    while(pos < len)
    {
        pos += process_data(data + pos);
    }
}
void callback_f(uint8_t *data, uint32_t len)
{
    //split data into parts
    uint32_t number_of_data_per_thread = len / number_of_threads;
    // Add work to ioService.
    uint32_t x = 0;
    for (i = 0; i < number_of_threads; i++)
    {   
         ioService.post(boost::bind(worker_task, data + x, number_of_data_per_thread));
         x += number_of_data_per_thread ;
    }
    // Now that the ioService has work, use a pool of threads to service it.
    for (i = 0; i < number_of_threads; i++)
    {   
        threadpool.create_thread(boost::bind(
            &boost::asio::io_service::run, &ioService));      
    }
    // threads in the threadpool will be completed and can be joined.
    threadpool.join_all();
}

因此,这个回调从主机应用程序(媒体流)调用得非常快。如果混合的len足够大,线程池是有意义的。这是因为工作时间高于线程和开始运行的初始时间。

如果数据的长度很小,那么线程池的优势就会丧失,因为初始化和启动线程比处理数据花费更多的时间。

现在可能的问题是,是否有可能让线程已经在运行并等待数据。如果回调被调用,则将数据推送到线程并等待其完成。线程数是恒定的(CPU计数)。因为它是来自主机应用程序的回调,所以指向数据的指针只有在回调函数中时才有效。这就是为什么我必须等到所有线程都完成工作。

线程可以在获取数据后立即开始工作,甚至在其他线程开始工作之前。并没有同步问题,因为每个线程都有自己的数据存储区。