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

Time:03-17

I'm getting a crash when calling interrupt() on an outer boost::thread, which runs an inner boost::thread, which is connected to a thread_guard. It's not crashing when calling join() manually on the inner thread.

Crash:
terminate called after throwing an instance of 'boost::thread_interrupted'

Source:
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;
}

Compile & Run:
http://coliru.stacked-crooked.com/a/46c512bf9a385fff

I'm running on Ubuntu 18.04. with g 7.5.0 and got the latest boost 1.78.0.

I opened this issue on github, too: https://github.com/boostorg/thread/issues/366

CodePudding user response:

You're mixing std::thread and boost::thread.

Only Boost Thread knows about interruption points. Use that to fix:

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;
}

Prints

Start
Interrupting outer
End

CodePudding user response:

I got a solution. The problem was, that the join() of the thread_guard waits for the inner thread with a condition_variable::wait(). condition_variable::wait() itself checks, if it's interruptible and throws an exception.

The solution is to use a custom thread_guard with disable_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");
}

Run here:
http://coliru.stacked-crooked.com/a/a365e40a2bd574cc

  • Related