在调试模式下运行时,抛出中断错误时会崩溃:
如何中断线程池,以及如何正确捕获中断(以及在调度作业或CancelAll中的位置?) 如果没有中断点,它不会崩溃,但线程不会被中断。当我设置中断点时,它会在发生中断错误时崩溃。
class ThreadAsioPool
{
public:
ThreadAsioPool(const std::size_t nb_threads);
virtual ~ThreadAsioPool() { CancelAll(); }
void CancelAll();
void AddJob(Wrapcontainer &wrap);
protected:
static void job(Wrapcontainer wrap);
void AddThread() {m_threadgroup.create_thread(boost::bind(&boost::asio::io_service::run, &io)); }
private:
std::size_t nbThreads;
boost::asio::io_service io;
boost::thread_group m_threadgroup;
boost::asio::io_service::work *work;
};
ThreadAsioPool::ThreadAsioPool(const std::size_t nb_threads): nbThreads(nb_threads)
{
work = new boost::asio::io_service::work(io);//will keep io busy so it won't stop
for (std::size_t i = 0; i < nbThreads; ++i)
AddThread();
}
void ThreadAsioPool::AddJob(Wrapcontainer &wrap)
{
//after a CancelAll, the m_threadgroup would be empty, so add more thread if needed
if (m_threadgroup.size() < nbThreads )
AddThread();
io.post(boost::bind(&ThreadAsioPool::job,wrap));
io.reset();
io.poll();
}
void ThreadAsioPool::CancelAll()
{
try{
io.stop();//not sure that's necessary to stop the queue from processing
m_threadgroup.interrupt_all(); //this to empty the queue
m_threadgroup.join_all();//I assume after this line that the m_threadgroup is empty
}
catch(boost::thread_interrupted const& e){
int i=0;//so I can put a breakpoint to see if it gets there, and it doesn't
i=1;
}
catch(std::exception const& e){
int i=0;//doesn't get here either
i=2;
}
catch(...){
int i=0;//doesn't get here either
i=3;
}
}
void ThreadAsioPool::job(Wrapcontainer wrap)
{
try{
boost::this_thread::interruption_point();
...some work..
boost::this_thread::interruption_point(); //inserting few interruption point between heavy task
...some work..
boost::this_thread::sleep(boost::posix_time::milliseconds(50)); //different type of breakpoint see if it makes a difference
...some work..
boost::this_thread::interruption_point();
}//try
catch(boost::thread_interrupted& e){
int i=0;//so I can put a breakpoint to see if it gets there, and it doesn't
i=1;
}
catch(std::exception const& e){
int i=0;//doesn't get here either
i=2;
}
catch(...){
int i=0;//doesn't get here either
i=3;
}
}
void main()
{
ThreadAsioPool threadpool(3);
//add 50 jobs in the queue
for (int i=0;i<50;i++){
Wrapcontainer itemdata;//just a class to contain data for the job
... fill up 'itemdata' with required data for the job
threadpool.AddJob(itemdata);//feed a job
}
threadpool.CancelAll();
}
答案 0 :(得分:1)
在AddJob
你已经完成了所有的工作。您不排队任何事情,执行是连续的: Simple Demo
Job Job 1 done main.cpp
2 done main.cpp
Job 3 done main.cpp
Job 4 done main.cpp
Job 5 done main.cpp
Job 6 done main.cpp
Job 7 done main.cpp
Job 8 done main.cpp
Job 9 done main.cpp
Job 10 done main.cpp
Canceling
通过执行reset()
和poll()
不来解决此问题(您已经让工作人员正在执行run()
,对吧?)。
样品(一分钟内):
<强> Live On Coliru 强>
此示例离开&#34;重置&#34;取消后的线程池/队列作为练习给读者。考虑 KISS :您可以在销毁期间始终取消
ThreadAsioPool
,并为更多工作创建新实例。这将具有完全所需的行为,而且编码没有复杂性。
#include <boost/thread.hpp>
#include <boost/asio.hpp>
struct Wrapcontainer {
int id = id_gen();
private:
static int id_gen() {
static int seed = 0;
return ++seed;
}
};
class ThreadAsioPool {
public:
ThreadAsioPool(const std::size_t nb_threads);
virtual ~ThreadAsioPool() { CancelAll(); }
void CancelAll();
void AddJob(Wrapcontainer &wrap);
protected:
static void job(Wrapcontainer wrap);
void AddThread() { m_threadgroup.create_thread(boost::bind(&boost::asio::io_service::run, &io)); }
private:
std::size_t nbThreads;
boost::asio::io_service io;
boost::thread_group m_threadgroup;
boost::optional<boost::asio::io_service::work> work;
};
ThreadAsioPool::ThreadAsioPool(const std::size_t nb_threads)
: nbThreads(nb_threads), io(),
work(boost::asio::io_service::work(io))
{
for (std::size_t i = 0; i < nbThreads; ++i)
AddThread();
}
void ThreadAsioPool::AddJob(Wrapcontainer &wrap) {
// after a CancelAll, the m_threadgroup would be empty, so add more thread if needed
if (m_threadgroup.size() < nbThreads)
AddThread();
io.post(boost::bind(&ThreadAsioPool::job, wrap));
}
void ThreadAsioPool::CancelAll() {
try {
work.reset();
io.stop(); // not sure that's necessary to stop the queue from processing
m_threadgroup.interrupt_all(); // this to empty the queue
m_threadgroup.join_all(); // I assume after this line that the m_threadgroup is empty
} catch (boost::thread_interrupted const &e) {
std::cout << "CAUGHT " + std::to_string(__LINE__) << "\n";
} catch (std::exception const &e) {
std::cout << "CAUGHT" + std::to_string(__LINE__) << "\n";
} catch (...) {
std::cout << "CAUGHT " + std::to_string(__LINE__) << "\n";
}
}
void ThreadAsioPool::job(Wrapcontainer wrap) {
try {
boost::this_thread::interruption_point();
boost::this_thread::interruption_point(); // inserting few interruption point between heavy task
boost::this_thread::sleep(boost::posix_time::milliseconds(50)); // different type of breakpoint see if it makes a difference
boost::this_thread::interruption_point();
std::cout << "Job " << wrap.id << " done " + std::to_string(__LINE__) << "\n";
} // try
catch (boost::thread_interrupted &e) {
std::cout << "CAUGHT " + std::to_string(__LINE__) << "\n";
} catch (std::exception const &e) {
std::cout << "CAUGHT " + std::to_string(__LINE__) << "\n";
} catch (...) {
std::cout << "CAUGHT " + std::to_string(__LINE__) << "\n";
}
}
int main() {
ThreadAsioPool threadpool(3);
// add 50 jobs in the queue
for (int i = 0; i < 50; i++) {
Wrapcontainer itemdata; // just a class to contain data for the job
//... fill up 'itemdata' with required data for the job
threadpool.AddJob(itemdata);//feed a job
}
std::cout << "Canceling\n";
threadpool.CancelAll();
}
打印
Canceling
CAUGHT 71
CAUGHT 71
CAUGHT 71
注意在CancelAllJobs
中捕获中断的异常有点滑稽(除非您想要防止在异常线程中调用异常时泄露异常)。< / p>