is deadlock possible with no static members?

  • Thread starter Thread starter mk
  • Start date Start date
M

mk

You probably suspect the answer, typically its 'yes'
deadlock can occur in any multithreaded application.
Even ones that employ static members. Commonly it occurs
when more than one thread tries to lock a resource that
another thread has already locked.
A workaround is to use the Monitor object's TryEnter
method, and pass a timeout value, if timeout occurs the
method returns false.
This pattern will save you no end of pain and suffering,
check it out on MSDN. Also I would recommend that you
record the number of deadlock situations (TryEnters that
return false), that occur during your testing -at least
in your debug builds. This may lead you to redefine the
distribution of effort in your application if you find
that contention for resources is undermining efficiency.

Incidentally you may also wish to investigate another
threading bugbear, race conditions, where dirty reads and
overwrites may occur is shared resources are not securely
locked during operations.

HTH,

MK
 
mk said:
You probably suspect the answer, typically its 'yes'
deadlock can occur in any multithreaded application.
Even ones that employ static members. Commonly it occurs
when more than one thread tries to lock a resource that
another thread has already locked.

That's not necessarily a problem at all. Contention will reduce
performance, but that's not the same as deadlock. Deadlock occurs when
there is a cycle of two or more threads, where each thread in the path
wants a lock that the next thread holds, etc until you get round to the
last thread wanting the lock that the first thread holds. Often this is
with two threads, but it can certainly be with more than that.
A workaround is to use the Monitor object's TryEnter
method, and pass a timeout value, if timeout occurs the
method returns false.
This pattern will save you no end of pain and suffering,
check it out on MSDN. Also I would recommend that you
record the number of deadlock situations (TryEnters that
return false), that occur during your testing -at least
in your debug builds. This may lead you to redefine the
distribution of effort in your application if you find
that contention for resources is undermining efficiency.

Incidentally you may also wish to investigate another
threading bugbear, race conditions, where dirty reads and
overwrites may occur is shared resources are not securely
locked during operations.

I personally would avoid the "workaround" for almost everything.
Multithreading is fundamentally pretty nasty, but I firmly believe that
the only way to do it properly is to lock only where you're sure you
need to, always think about things so that you're sure one way or the
other, and clearly document thread safety. Testing will get you so far,
but race conditions and deadlocks always seem to end up happening in
the field rather than on test machines. A strong model of what should
go on is much, much better than a "try it and fix where it doesn't
work" approach. (You didn't exactly suggest that, but it seems to be
where it was going.)
 
Hi,
Regarding contention v. deadlock you're quite correct, I
should have elaborated my example a little further.
Regarding your comments on 'workaround', I'm afraid that
not all multithreaded apps are deterministic. It does
depend on the runtime env. which can lead to
unpredictable behaviour in the field. Perhaps the
term 'workaround' was also a poor choice, what I meant
was that when in doubt, or where there is potential for
doubt, don't expose yourself to deadlock, and especially
so in distributed apps where networks may have failed, db
connections may have failed, etc. Rather, don't just
blindly call lock, give yourself an 'outie'.

Kind regards,

Martin
 
mk said:
Regarding contention v. deadlock you're quite correct, I
should have elaborated my example a little further.
Regarding your comments on 'workaround', I'm afraid that
not all multithreaded apps are deterministic. It does
depend on the runtime env. which can lead to
unpredictable behaviour in the field. Perhaps the
term 'workaround' was also a poor choice, what I meant
was that when in doubt, or where there is potential for
doubt, don't expose yourself to deadlock, and especially
so in distributed apps where networks may have failed, db
connections may have failed, etc. Rather, don't just
blindly call lock, give yourself an 'outie'.

Hmm... While I can see that would *occasionally* be useful in those
circumstances (although if you've got a thread waiting forever for a
network connection or a database, you've got other major problems
anyway), I really wouldn't want to use it very often at all.
 
mk said:
You probably suspect the answer, typically its 'yes'
deadlock can occur in any multithreaded application.
Even ones that employ static members. Commonly it occurs
when more than one thread tries to lock a resource that
another thread has already locked.
A workaround is to use the Monitor object's TryEnter
method, and pass a timeout value, if timeout occurs the
method returns false.
This pattern will save you no end of pain and suffering,
check it out on MSDN. Also I would recommend that you
record the number of deadlock situations (TryEnters that
return false), that occur during your testing -at least
in your debug builds. This may lead you to redefine the
distribution of effort in your application if you find
that contention for resources is undermining efficiency.

Incidentally you may also wish to investigate another
threading bugbear, race conditions, where dirty reads and
overwrites may occur is shared resources are not securely
locked during operations.

Jon has said it all and I couldn't agree more. Multithreading is a all about
thinking very hard before you code and much less about trial and error. It
is always a very good idea to have MT code reviewed by someone who really
knows MT, *before you start integrating it*. Multithreading bugs are
tyically very hard to track down (deadlocks are easiest).

Regards,

Andreas
 
You think it would *occassionally* be useful in those
circumstances? Can you describe a situation where you
think the majority applies in those circumstances. I've
spent 20 years writing multithreaded distributed apps,
and we always protect ourselves against undeclared
resource outage.
Please understand that this is meant in uberrimae fides,
and not some attempt at flame-propagation.
I think that in the .Net scenario, C# in particular, we
don't always have full control, and we need to ensure
that attempts to acquire async resources should be
controlled.

Kind regards,

Martin
 
Andreas Huber said:
Jon has said it all and I couldn't agree more. Multithreading is a all about
thinking very hard before you code and much less about trial and error. It
is always a very good idea to have MT code reviewed by someone who really
knows MT, *before you start integrating it*. Multithreading bugs are
tyically very hard to track down (deadlocks are easiest).

The difficulty here is finding someone who really knows MT to start
with. I'd like to think I know more than most casual programmers, but I
wouldn't like to really certify things as safe :)

(I'm more than happy to lend my opinion, of course, as regulars here
are all too well aware ;)

One of my favourite understatements was on comp.lang.java.programmer,
from one of the very well respected regulars:
"Multi-threaded programming needs a little care."
 
mk said:
You think it would *occassionally* be useful in those
circumstances?

I expressed it badly: I think it's occasionally useful, because I think
those circumstances occur rarely.
Can you describe a situation where you
think the majority applies in those circumstances. I've
spent 20 years writing multithreaded distributed apps,
and we always protect ourselves against undeclared
resource outage.

Surely it's only undeclared resource outage that has *already* tied up
a thread indefinitely that causes this problem, isn't it? That's what I
find pretty rare. Usually, if a network or database fails, the thread
isn't going to deadlock - the method is going to throw an exception or
return a failure code.

I guess you could end up making a request to a webserver or database
which deliberately holds the connection forever, or somesuch - but then
I think you're likely to be in deep problems already, and TryEnter
isn't going to help that much.
Please understand that this is meant in uberrimae fides,
and not some attempt at flame-propagation.
I think that in the .Net scenario, C# in particular, we
don't always have full control, and we need to ensure
that attempts to acquire async resources should be
controlled.

It seems to me that by the time this kind of thing happens the program
is likely to be sufficiently screwed up that actually deadlock might be
one of the safest courses of action - it at least can't then corrupt
any data. The only other alternative (that I can see) is to abort the
program completely - you're probably no longer in a viable situation to
get on with work reliably. Admittedly that alternative may well be
better than deadlocking - at least in some ways.

Your suggestion came over as though the code should be peppered with
TryEnter. That necessitates manually calling Exit, which I suggest is
more likely to cause problems in the long run, as I suspect the average
developer is less likely to hit deadlock through catastrophic failure
than they are to cause bugs by failing to call Exit properly in all
cases, causing potential deadlock or even data corruption in far less
dire circumstances than the catastrophic ones talked about above.
 
mk said:
I do agree. Naturally, so many of the rt vars apply to
very specific scenarios. I didn't mean to suggest that
TryEnter should be the prevalent means. I do hope that
no offense was caused or taken. I do enjoy reading
through this newsgroup from time to time, and always your
responses show diligence.

Absolutely no offence taken - and to be honest, it sounds like you do
have a lot more experience in some very difficult scenarios than I do.
Apologies if I've pushed my corner a bit too hard, as it were :)

I suspect we've just miscommunicated/misunderstood the each other a bit
- but no harm is done on this side, and I hope the feeling's mutual.
 
Back
Top