I would like to make the program wait till it finishes all the running threads unlike ioService.stop();
, which stops the ioService
without waiting. I tried the following code,which is working fine but stoping the ioService
without waiting for the threads to finish.
#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;
}
Compile with : -lboost_serialization -lboost_thread -lboost_system
Your problem is that you are creating work
as a variable on the stack. work
tells the io_service that there is still work to be done. From the manual:
Destructor notifies the io_service that the work is complete.
Since work is created in main on the stack, it's lifetime is longer than you want it to be. It will not be destructed until main exits. Create it on the heap instead, so you can explicitly destroy it. Change it to:
using namespace boost::asio;
boost::scoped_ptr<io_service::work> work(new io_service::work(ioService));
Then, later, when you want to tell io_service to stop after it has finished all outstanding work, don't stop io_service but destroy 'work' instead, then wait for the thread to finish.
work.reset();
threadpool.join_all();
This will call ~work()
, which will remove the work object from the io_service. That in turn will cause io_service::run
to exit when the last pending operation has finished.
A few more notes:
io_service::work work(io_service);
It's too confusing. I would write something like io_service::work some_work(io_service);
io_service.post(... std::ref(str));
You are passing a reference to the io_service post action. The variable str must live long enough for the task to finish. I am sure this is here just for the example. In real world applications it can be surprisingly hard to ensure that parameters passed to work objects are not destructed prematurely. I use shared_ptr<>
a lot or, in cases where that is not possible, I sometimes count the number of outstanding io_service actions with a boost::atomic