I have recently been experiencing bad karma when stopping my threads and I cannot figure out what I am doing wrong. I have not had these issues from before, so it might be related to upgrading to Juce 3.2.0, although it has worked fine for a month or so with the new version. The issue only arises now and then, however, so I might just have been lucky so far.
I run into the bad karma jassertfalse here (juce_Thread.cpp):
bool Thread::stopThread (const int timeOutMilliseconds)
{
// agh! You can't stop the thread that's calling this method! How on earth
// would that work??
jassert (getCurrentThreadId() != getThreadId());
const ScopedLock sl (startStopLock);
if (isThreadRunning())
{
signalThreadShouldExit();
notify();
if (timeOutMilliseconds != 0)
waitForThreadToExit (timeOutMilliseconds);
if (isThreadRunning())
{
// very bad karma if this point is reached, as there are bound to be
// locks and events left in silly states when a thread is killed by force..
jassertfalse;
Logger::writeToLog ("!! killing thread by force !!");
killThread();
threadHandle = nullptr;
threadId = 0;
return false;
}
}
return true;
}
NetworkExplorer.h
class NetworkExplorer : public juce::Thread
{
// Other non-related stuff here
private:
juce::ScopedPointer<DatagramSocket> mSocket;
boolean mExploring;
}
NetworkExplorer.cpp
NetworkExplorer::NetworkExplorer(bool enableBroadcasting = false) : juce::Thread("NetworkExplorer"),
{
// The below used to be
// mSocket = new DatagramSocket(55555, enableBroadcasting)
// before updating Juce version.
mSocket = new DatagramSocket(enableBroadcasting);
mSocket->bindToPort(55555);
}
NetworkExplorer::~NetworkExplorer()
{
// Used to have
// mSocket->close();
// here before updating Juce version.
mExploring = false;
this->stopThread(1000);
}
// Other non-related functions, including NetworkExplorer::run().
void NetworkExplorer::startExploring()
{
mExploring = true;
this->startThread();
}
Now, the instance of the NetworkExplorer class lives in another class as ScopedPointer:
private:
ScopedPointer<NetworkExplorer> mNetworkExplorer;
It is created like this in the owner class constructor:
mNetworkExplorer = juce::ScopedPointer<NetworkExplorer>(new NetworkExplorer(false)); mNetworkExplorer->startExploring();
And destroyed in the owner class destructor:
// This is where the code digs into Thread::stopThread() and bad karma is applied. mNetworkExplorer = nullptr;
Is this not the proper way to create and destroy a custom Thread? What am I doing wrong?
