MessageManagerLock freeze when being constructed


#1

Hello.

I got some part of my code that could be repeated by user actions, at high frequencies.

The part of code begin with a “const MessageManagerLock mmLock”.
And when it freezes, the stack points to a semaphore_wait_signal_trap
and goes back to :

MessageManagerLock::MessageManagerLock() throw() : locked (false) { if (MessageManager::instance != 0) { [b] gdb-> MessageManager::instance->messageDispatchLock.enter();[/b] lastLockingThreadId = MessageManager::instance->currentLockingThreadId; MessageManager::instance->currentLockingThreadId = Thread::getCurrentThreadId(); locked = true; }

Here is my stack :[quote]
sematphore_wait_signal_trap
pthread_mutex
juce::CriticalSection::enter
juce::MessageManagerLock::MessageManagerLock[/quote]

Hope someone can help to understand where there is the hassle, or how to patch it.

I think, by getting backer in the stack, that there is conflits between my own Lock and some MessageManager and HIView lock.
It works better when i comment my Lock.
IS there a way to active lock only if possible or so on…?

thanks
AsR


#2

You’ve got a deadlock. If you’re not 100% sure what a deadlock is, go and learn about them properly, then try debugging it again, and it’ll probably be easy to see what you’ve done wrong.


#3

I think I know what is it. But not “100%” so… i’ll learn a bit more.

But… how could I get such a deadLock when mmLock is done to avoid them ?..


#4

Yeah, that shows that you don’t know what a deadlock is!


#5

:lol:


#6

[quote]
Yeah, that shows that you don’t know what a deadlock is![/quote] :lol:
thank you for your patience.


#7

NAh… I read enough things about DeadLock. This is just a name about a phenomenon I already knew.

I dont have any deadlock sources in my own code, things come so from my utilisation of the API…

How is possible to generate a deadlock with mmlock sequential use ???

I have one thread only added to the main one. He just ask some repaint after lock as detailed in Juce doc…

Confusing.


#8

i don’t know why you can’t see how using a mmlock can get you into a deadlock situation; you can only get into a deadlock through using locks… that is how they occur. The message manager lock is a lock for the message thread; a lock is not to prevent deadlocks, it is to allow thread safety; deadlocks are the result of improper use of locks.


#9

Anyway, how could anyone on earth give a proper answer without first looking at the code that causes these deadlocks?


#10

Yep.

To state first what a deadlock if ever needed :[quote]A system where multiple threads coexist in the same address space is extremely vulnerable to data corruption and deadlock. While there is a trade-off between these two problems, deadlock remains the ultimate bug and is almost impossible to eradicate.

This article will discuss a technique for detecting and breaking deadlocks in a multithreaded environment. It will also present a simple and powerful way to analyze why the deadlock occurred.

A deadlock is a situation where each thread in a set of at least two threads is waiting for a resource (shared data is also considered a resource), which is locked by another thread in the set. The result is that each thread in the set is waiting indefinitely for the resources to be released. [/quote]

Then here is the simple diagram of my app :

The engine thread updates - many times during a user session - the GUI, with 3 callbacks (static functions):

//In the concerned class S_SequencerPrincipal_address = this; m_engines-> addCrossAControlPointAction (& controlPointHasBeenDone); m_engines-> addWaitedTriggerPointMessageAction (& waitedTriggerPointCallBack); m_engines-> addIsExecutionFinishedAction (& isExecutionFinished);

Each callback calls main object of JuceAPP by the given address.

Finally here are my source functions troubling :

static Sequencer* s_SequencerPrincipal_address = NULL;


    /* if component methods are being called from threads other than the message
     thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
     line 1641    checkMessageManagerIsLocked
	 line 341 pas de thread current*/

static void controlPointHasBeenDone(unsigned int boxId, unsigned int controlPointIndex){
	
	if(s_SequencerPrincipal_address==NULL) return;
	
	const MessageManagerLock mmLock()) ;
	
	s_SequencerPrincipal_address->getLedOut()->setVisible(true);
	
	jassert(controlPointIndex > 0);
	jassert(s_SequencerPrincipal_address->getBox(boxId) > 0);
	
	s_SequencerPrincipal_address->getBox(boxId)->controlPointHasBeenDone(controlPointIndex);
	switch (controlPointIndex) {
			case 1:
				s_SequencerPrincipal_address->showComments(boxId);
				break;
			default:
				s_SequencerPrincipal_address->removeComment(boxId);
				break;
	}
	s_SequencerPrincipal_address->getLedOut()->fadeOutComponent(50,0,0,0);
	s_SequencerPrincipal_address->repaint();
};

static void waitedTriggerPointCallBack(bool isWaited, unsigned int triggerId, unsigned int boxId, unsigned int controlPointIndex, std::string triggerMessage){
	
	if(s_SequencerPrincipal_address==NULL) return;
	
	const MessageManagerLock mmLock();	
	
	s_SequencerPrincipal_address->getLedIn()->setVisible(true);
	
	s_SequencerPrincipal_address->getTrigger(triggerId)->waitedTriggerPointCallBack(isWaited);
	
	if(isWaited){
			s_SequencerPrincipal_address->appendTriggeredBoxComment("[o] " + s_SequencerPrincipal_address->getBox(boxId)->getTitle() + ": " + s_SequencerPrincipal_address->getBox(boxId)->getComment());
	}
	else  {
			s_SequencerPrincipal_address->removeComment (boxId);
	}
	
	s_SequencerPrincipal_address->getLedOut()->fadeOutComponent(50, 0,0,0);
	s_SequencerPrincipal_address->repaint();
};

static void isExecutionFinished() {
	
	if(s_SequencerPrincipal_address==NULL) return;
	
	const MessageManagerLock mmLockNess;
	
	s_SequencerPrincipal_address->getController()->stop();
	
	s_SequencerPrincipal_address->repaint();
};

Download file here: http://27sens.com/deadlockingfil.zip

And finally, the god stack: semaphore_wait_signal_trap pthread_mutex_lock juce::CriticalSection::enter juce::MessageManagerLock::MessageManagerLock juce::MessageManager::deliverMessage EventHandlerProc ...

More info by there for any has time on it: http://27sens.com/deadlock.pdf

Thank you for any help you’ll take time to give.
AsR


#11

I can’t make much sense out of all that lot, and haven’t time to spend going through it, but deadlocks are usually very easy to debug - when you stop the app, two threads will be sitting there inside critical section callbacks, and you just need to have a quick look on their stacks to see what else they’ve got locked to see what’s going on.

One situation I’ve often hit which isn’t always obvious is where the message thread is calling stopThread on a thread that is using an mmlock.


#12

Whatever, after many reviews, the fact is something always often mentionned in Juce forum topics.

It seems like MessageManagerLock does not unlock, and MessageManager waits infinitely for.

However, I tried different way to ensure MessageManagerLock was correctly destroyed once used. It seems not to.

I got a deadlock between
Thread 1 (juce::CriticalSection::enter)
& Thread 2 (WaitableEvent)


#13

Well, apart from your steadfast refusal to accept that you’re causing a deadlock, looking through your code, you have recreated a single-threaded app.

When your thread functions lock the MM, they are essentially blocking the main thread, which is the same as running on the main thread - both threads are locked together at that point.

In that case (and bearing in mind this isn’t the best solution, merely the one that fits with the compromises you’ve already made), just send a message with your changes. Then the main thread will get the message and act on it - bingo, no threading problems at all.

Then you can always go back and re-educate yourself if that solution actually seems to need to keep working on both threads.

Bruce


#14

[quote]apart from your steadfast refusal to accept that you’re causing a deadlock[/quote]First, i dont refuse, this is a question of time. I 'm not given time to properly track down the deadlock - moreover i get no way to exchange with the man who develops the third-party thread who callbacks. This is a fact. No need for more details. I’m sorry with that.

Thank you much for having looking details of my codes.

[quote]
When your thread functions lock the MM, they are essentially blocking the main thread, which is the same as running on the main thread[/quote]
what I actually targetted…

[quote]

  • both threads are locked together at that point. [/quote]What obviously I did not understood. Main thread is locked: ok. Why locking thread is locked too ?

[quote]
just send a message with your changes[/quote] I switch to that and solved: http://www.rawmaterialsoftware.com/juceforum/viewtopic.php?t=4167


#15

You don’t need the other guy - he can’t have caused the deadlock, as he can’t access Juce’s locks.

When you lock the main thread, then do a whole lot, you’re obviously accessing something that needs to lock the main thread itself. It fails, since you’ve locked it. Deadlock.

Your solution using the MMLock means the main thread has to stop what it’s doing (certainly anything useful) and wait for you to finish. This means both threads are linked together for this period.

A more normal way to address the problem would be:

myCallback()
{
work stuff out
work more stuff out
get all ready

lock the MM
   do the absolute minimum that I need to be locked for
Unlock the MM

}

I would even personally wrap the stuff that needs a lock into another function, say:
controller->quicklyDoStuffThatNeedsALock(params)

Bear in mind a fair amount of stuff, like repaint, doesn’t need locking.

Bruce

PS When I referred to your steadfast refusal, I didn’t mean to debug, I meant to listen to the 3 or 4 people (including Jules!) who told you what the problem was. Jules even told you how to work it out. You know the stack you showed:

[quote]semaphore_wait_signal_trap
pthread_mutex_lock
juce::CriticalSection::enter
juce::MessageManagerLock::MessageManagerLock
juce::MessageManager::deliverMessage
EventHandlerProc [/quote]

Didn’t it occur to you that you have a threading problem, and that’s the stack from one thread? The other thread probably has a better clue.


#16

[quote]
When you lock the main thread, then do a whole lot, you’re obviously accessing something that needs to lock the main thread itself. It fails, since you’ve locked it. Deadlock. [/quote]Very good to know!

Many things in what you say, that i agree and tested :

[quote]Your solution using the MMLock means the main thread has to stop what it’s doing (certainly anything useful) and wait for you to finish. This means both threads are linked together for this period. [/quote]what I aim… actually.

[quote]
myCallback()
{
work stuff out
work more stuff out
get all ready

lock the MM
do the absolute minimum that I need to be locked for
Unlock the MM
} [/quote]

I went towards that way of doing, just because it is moderated.
But it did not change a lot things.

So then I took care not to encapsulate things too much.

The fact is that i always found a time where it deadlocked.

[quote]
Bear in mind a fair amount of stuff, like repaint, doesn’t need locking.[/quote]
Oh oh … apologize… :oops: Are you sure though ? I got jassert when repaint w/o Lock.

I think I ask something to lock the main thread, which is already locked, => deadlock. (as you say)
I suspect e.g. fadeOutComponent (but this is maybe naive)

Great thanks.

////
fadeOutComponent commented, things better.


#17

Just to clarify: you do need to lock around a repaint() call - just like any other Component methods, because obviously even a simple call like repaint will mess up if another thread happens to delete or alter a component while you’re using it.

But no, fadeOutComponents can have nothing to do with a deadlock - it doesn’t use threads, so how could it?