ryanpxu's picture

Hello Mike,

I have been trying out pion recently. I have this question after checking out PionScheduler source. In startup() function, you created a bunch of threads and insert them into a list:
"
// start multiple threads to handle async tasks
for (boost::uint32_t n = 0; n < m_num_threads; ++n)
{
boost::shared_ptr new_thread(new boost::thread( boost::bind(&PionScheduler::run, this) ));
m_thread_pool.push_back(new_thread); }
"

My understanding is for each scheduler instance there will be a pool of threads working on same boost::asio::io_service object. Given it is thread safe, it makes perfect sense. However I don't see any code of collaboration among threads. Like when requests are coming in, which available thread will handle it. And once a thread is done with its work, how it will become available again. What if there are many requests coming in and we starve on threads, is there any message queue for'em?

In summary, I was surprised to see how little threading code is comparing to ASIO in PionScheduler. I am not very familiar with boost thread and asio library, maybe all magics happen underhood? Please give me some hints, thanks.

Regards,
PX

Mike Dickey's picture
It's all in io_service

Most of the magic is handled by asio's io_service object.

Threads that call asio::io_service::run() basically just block until work is available. io_service handles the work queue that is generated by calls to io_service.post() as well as any asynchronous calls that make use of the service. It also handles passing work along to the threads. So long as there is work (of any kind) available in the io_service, the threads continue to block & wait for more work after completing each task.

In 0.5.4 and previous versions, we let the work expire and had the threads running in a loop that either slept or called io_service::run() repeatedly. Since then, we've found that a cleaner approach (and one that appears to be much more efficient) is to just post an asynchronous asio::deadline_timer that repeatedly keeps re-scheduling itself (until it's time to shut down). This ensures that the io_service always has some work available, and keeps the threads from returning.

Actually, this is the recommended approach for using io_service with a thread pool. I just started out with the old method and haven't had a chance (or reason) to change it until recently..

Note that the latest subversion code includes this and also adds more flexibility to PionScheduler. For example, there is now an option to use a separate io_service for each thread in the pool, and you can also more easily extend it to try other approaches as well.

Submitted by Mike Dickey on Sun, 04/06/2008 - 14:54.