在一个boost::线程上调用interrupt()时崩溃,该线程有另一个boost::线程



在运行连接到thread_guard的内部boost::thread的外部boost::thread上调用interrupt()时出错。在内部线程上手动调用join()时不会崩溃。

崩溃:
terminate called after throwing an instance of 'boost::thread_interrupted'

来源:
https://gist.github.com/elsamuko/6e178c37fa2cf8742cb6bf512f2ff866

#include <iostream>
#include <thread>
#include <boost/thread/thread.hpp>
#include <boost/thread/thread_guard.hpp>
#define LOG( A ) std::cout << A << std::endl;
void double_interrupt() {
boost::thread outer([] {
boost::thread inner([]{
while(true) {
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
});
{
std::this_thread::sleep_for(std::chrono::milliseconds(1));
LOG("Interrupting inner");
boost::thread_guard<boost::join_if_joinable> guard(inner);   // crashes
// inner.join(); // works
}
});
LOG("Interrupting outer");
outer.interrupt();
outer.join();
}
int main(int argc, char* argv[]) {
LOG("Start");
double_interrupt();
LOG("End");
return 0;
}

编译&运行:
http://coliru.stacked-crooked.com/a/46c512bf9a385fff

我在Ubuntu 18.04上运行。g++7.5.0,并获得1.78.0的最新提升。

我也在github上打开了这个问题:https://github.com/boostorg/thread/issues/366

您正在混合std::threadboost::thread

只有Boost线程知道中断点。用它来修复:

在Coliru上直播

#include <iostream>
#include <thread>
#include <boost/thread.hpp>
#include <boost/thread/thread_guard.hpp>
void double_interrupt() {
boost::thread outer([] {
boost::thread inner([] {
while (true) {
boost::this_thread::sleep_for(boost::chrono::milliseconds(1));
}
});
{
boost::this_thread::sleep_for(boost::chrono::milliseconds(1));
std::cout << "Interrupting inner" << std::endl;
boost::thread_guard<boost::join_if_joinable> guard(inner);
}
});
std::cout << "Interrupting outer" << std::endl;
outer.interrupt();
outer.join();
}
int main() {
std::cout << "Start" << std::endl;
double_interrupt();
std::cout << "End" << std::endl;
}

打印

Start
Interrupting outer
End

我得到了一个解决方案。问题是,thread_guardjoin()等待具有condition_variable::wait()的内线程。condition_variable::wait()本身会检查它是否可中断并抛出异常。

解决方案是使用带有disable_interruption:的自定义thread_guard

#include <iostream>
#include <thread>
#include <boost/thread.hpp>
#include <boost/thread/thread_guard.hpp>
#define LOG( A ) std::cout << A << std::endl;
void work() {
size_t sum = 0;
for(int i = 0; i < 1E7; ++i) { sum += 1; }
LOG("work: " << sum);
}
// helper struct to interrupt a boost::thread within a boost::thread
struct non_interruptable_interrupt_and_join_if_joinable {
template <class Thread>
void operator()(Thread& t) {
if(t.joinable()) {
boost::this_thread::disable_interruption di;
t.interrupt();
t.join();
}
}
};
void double_interrupt() {
boost::thread outer([] {
boost::thread inner([] {
while(true) {
boost::this_thread::interruption_point();
work();
}
});
{
boost::thread_guard<non_interruptable_interrupt_and_join_if_joinable> guard(inner);
LOG("Interrupting inner");
}
});
LOG("Interrupting outer");
outer.interrupt();
outer.join();
}
int main() {
LOG("Start");
double_interrupt();
LOG("End");
}

在此处运行:
http://coliru.stacked-crooked.com/a/a365e40a2bd574cc

最新更新