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?