在每个线程完成后停止 io_service
Stopping the io_service after every thread is finished
我想让程序等到它完成所有 运行 个线程,这与 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
您的问题是您正在创建 work
作为堆栈上的变量。 work
告诉 io_service 还有工作要做。来自手册:
Destructor notifies the io_service that the work is complete.
由于工作是在堆栈中的 main 中创建的,因此它的生命周期比您希望的要长。在 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
在最后一个挂起的操作完成时退出。
更多注意事项:
- 我会避免给变量赋予与其 class 相同的名称。我不会写
io_service::work work(io_service);
太乱了。我会写类似 io_service::work some_work(io_service);
- 小心
io_service.post(... std::ref(str));
您正在传递对 io_service post 操作的引用。变量 str 必须存在足够长的时间才能完成任务。我确信这只是为了举例。在现实世界的应用程序中,确保传递给工作对象的参数不会过早销毁可能出奇地困难。我经常使用 shared_ptr<>
,或者在不可能的情况下,我有时会用 boost::atomic 计算未完成的 io_service 操作的数量
我想让程序等到它完成所有 运行 个线程,这与 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
您的问题是您正在创建 work
作为堆栈上的变量。 work
告诉 io_service 还有工作要做。来自手册:
Destructor notifies the io_service that the work is complete.
由于工作是在堆栈中的 main 中创建的,因此它的生命周期比您希望的要长。在 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
在最后一个挂起的操作完成时退出。
更多注意事项:
- 我会避免给变量赋予与其 class 相同的名称。我不会写
io_service::work work(io_service);
太乱了。我会写类似io_service::work some_work(io_service);
- 小心
io_service.post(... std::ref(str));
您正在传递对 io_service post 操作的引用。变量 str 必须存在足够长的时间才能完成任务。我确信这只是为了举例。在现实世界的应用程序中,确保传递给工作对象的参数不会过早销毁可能出奇地困难。我经常使用shared_ptr<>
,或者在不可能的情况下,我有时会用 boost::atomic 计算未完成的 io_service 操作的数量