I have a state machine being processed within a std::thread. This state machine initializes a network connection, processes data, and upon the receipt of a certain message, needs to shut itself down. Using join in this fashion triggers the 'abort() has been called' exception. Is this one of the cases where a detached thread is appropriate.
#include <iostream>
#include <thread>
#include <atomic>
#include <memory>
class ThreadExample
{
public:
ThreadExample()
{
StartThread();
}
void StartThread()
{
//start thread;
run_thread = true;
the_thread = std::thread(&ThreadExample::ThreadFunction, this);
}
void ThreadFunction()
{
while (run_thread)
{
if (correct_message_found)
ShutdownThread();
else
ProcessMessage(); //example code to imitate network processing
//arbitrary wait. not relevant to the problem
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
//read in by some network connection
void ProcessMessage(/*some message data*/)
{
static int counter = 0;
if (counter == 3)
{
correct_message_found = true;
}
else
{
std::cout << "Waiting for the right message\n";
counter++;
}
}
void ShutdownThread()
{
run_thread = false;
if (the_thread.joinable())
the_thread.join();
}
private:
std::thread the_thread;
std::atomic_bool run_thread;
bool correct_message_found = false;
};
int main()
{
auto example = std::make_unique<ThreadExample>();
int data;
std::cin >> data;
}
The correct way to terminate a thread from inside itself is to simply return from the function the thread is executing:
void ThreadFunction()
{
while (run_thread)
{
if (correct_message_found)
return;
else
ProcessMessage(); //example code to imitate network processing
//arbitrary wait. not relevant to the problem
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
Calling join
from within the thread that is supposed to be joined is an error, see the first error condition: https://en.cppreference.com/w/cpp/thread/thread/join
join
means "wait for the given thread to finish, then continue on". You are telling a thread to wait until it itself is finished. So it can only end once it has already ended, which is clearly contradictory.
Where you should call join
is in the destructor of ThreadExample
. ThreadFunction
uses members of ThreadExample
, and ThreadExample
also owns the std::thread
object, so ThreadExample
cannot be allowed to die while the thread is still running. In the code you show, you would run into that problem if you input something before the thread is done: ThreadExample
is then destroyed, and with it the std::thread
object living inside. If a std::thread
is destroyed while joinable (i.e. with a non-detached thread still running) then std::terminate
is called:
https://en.cppreference.com/w/cpp/thread/thread/%7Ethread