在 boost::thread 上调用 interrupt() 时崩溃,其中有另一个 boost::thread

Crash when calling interrupt() on a boost::thread, which has another boost::thread

在运行内部 boost::thread 的外部 boost::thread 上调用 interrupt() 时发生崩溃,后者连接到 thread_guard。在内部线程上手动调用 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 并获得最新的 boost 1.78.0.

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

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

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

Live On 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() 自己检查是否可中断并抛出异常。

解决方案是使用自定义 thread_guarddisable_interruption:

#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