if (Atomic::decrementAndReturn (text->refCount) == 0)
juce_free (text);
text = other.text;
}
return *this;
}
My scenario is fairly simple:
non-message thread is assigning different status messages to a String and calling triggerAsyncUpdate (a lot);
message thread is assigning the status message String to a label.
By the way, I was being careful and using a critical section, but got caught out with a const String& returning outside of the critical section. Once I replaced this with a const String return everything seems OK.
What seemed to be happening was that both threads managed to call String::operator= at the same time. The first one decrements refCount to zero and calls free. Then, before it gets a chance to execute text = other.text, the second thread increments the ref count to one and copies the free’d text. Next time round the text is free’d for a second time, causing the crash.
Obviously, using a Critical Section and being very careful with const String& solves the problem, but I wonder if anyone else has any thoughts on this.
I just found out that my problems with heap corruption were due to this bug. Is there a quick’n’dirty fix for this? I have tried exchanging String.cpp/.h but that does not work so easily. I want to keep JUCE146, because it would require too much code changes (days of work) to adapt to the new JUCE.
I think I had to create a new “exchange” atomic op to avoid this problem, so it’d be pretty hard to back-port. Especially since the whole string class and atomic ops design has also changed since then!
Just wanna ask, do you think this is enough to solve the problem (seems to work here). I’ve added a lock that prevents the Labels accessing the statusMessages while they are being changed:
[code]// called from another thread!
void ThreadWithProgressWindowEx::setStatusMessage(int n, const String &message)
{
{
ScopedLock lock(statusMessageLock);
if (n==0) statusMessage=message;
else statusMessage2=message;
}
sendChangeMessage(this);
}
// called on GUI thread
void ThreadWithProgressWindowEx::changeListenerCallback(void *obj)
{
if (obj==this)
{
ScopedLock lock(statusMessageLock);
label->setText(statusMessage, false);
label2->setText(statusMessage2, false);
}
}[/code]
I wouldn’t do it that way - looks a bit risky for deadlocks between your lock and the messagemanagerlock. Better to use a messagemanagerlock around the place where you set the text.