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:
- What's the reason for this?
- 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.