Home > Blockchain >  abort() is called when I try to terminate a std::thread
abort() is called when I try to terminate a std::thread

Time:08-17

Note: I'm using WinForms & C 17.


So I was working on a school project. I have this function:

bool exs::ExprSimplifier::simplify()
{
    bool completed = false;

    std::thread thread1(&ExprSimplifier::internalSimplity, this, std::ref(completed));

    while (true)
    {
        if (completed)
        {
            thread1.~thread(); // calls abort()
            return true;
        }

        if (GetAsyncKeyState(27))
        {
            thread1.~thread(); // calls abort()
            return false;
        }
    }
}

Basically what I want is to run the following function:

// at the end of this function, I set completed = true
void exs::ExprSimplifier::internalSimplity(bool& completed)

..on another thread. I also want to check while the function's doing it's thing and the user pressed esc key, the thread terminates. But there's where I'm facing issues. This:

thread1.~thread();

..is calling abort(), crashing the application. Now what I think is that this is due to some scope thing of std::thread, but I'm not really sure.


Questions:

  1. What's the reason for this?
  2. What can I do to fix this?

CodePudding user response:

You can't terminate threads - end of story. In the past, they tried to make it so you could terminate threads, but they realized it's impossible to do it without crashing, so now you can't. (E.g. Windows had a TerminateThread function, because it's old. C doesn't have it, because C threads are new)

The only thing you can do is set a variable that tells the thread to stop, and then wait for it to stop.

~thread doesn't terminate threads, anyway. All it does is check that you remembered to call join or detach, and if you forgot to call one of them, it aborts, as you are seeing.

CodePudding user response:

What you typically want to do is something along this general line:

class doWhatever {
    std::atomic<bool> stop {false};
    std::thread t;
public:
    void run() { 
        t = std::thread([] { 
            while (!stop) {
                doSomeProcessing();
            }
        });
    }

    void stop() { 
        stop = true;
    }

    ~doWhatever() { 
        if (t.joinable())
            t.join();
    }
};

Exactly what you're going to do in doSomeProcessing obviously varies depending on what you really want your thread to do. Some threads have a queue of incoming tasks, and check the variable before processing each incoming task. Others have one long task to do, but if they do there's typically some loop there that you can check the variable at each iteration.

At least in my opinion, for a lot of situations, the ideal is that you check whether you've been asked to shut down something like once very 100 ms. This gives a nice balance--to a person, shutting down with 100 ms of telling it to looks nearly instantaneous, but you're still checking it infrequently enough that it doesn't affect execution speed enough to notice.

If you have a new enough compiler to support it, you may prefer to use std::jthread instead of std::thread. It basically includes an equivalent of the std::atomic<bool> in the thread object.

  • Related