deadlocks

B

blmblm

1 represents a lock A lock that is required to modify various things. I
happened to choose a simple example with just one variable A.


Which is caused because you unlocked too early! This madness, you are
agreeing with me whilst disagreeing :).

But the "too early" is "too early relative to modifying A", not "too
early relative to releasing other locks." If you released all three
locks in the order you think proper (reverse of acquisition order),
and then modified A, you would have the same problem, no?
From what I have read in this
discussion if you don't believe the
release-in-reverse-order-to-acquisition rule you won't agree with the
rest of what I've written.

You're right. You haven't said anything that convinces me that
there are safety problems caused by the order in which one releases
locks.
I probably shouldn't have mentioned any of this at all as it doesn't
apply to Java due to the way the language is constructed. We don't
appear to be getting anywhere with this so best to leave it. It appears
that you have come to the same conclusion.

Pretty much. I'm troubled by the contradiction between what you say
(which sounds like it's based on real-world experience) and what
I understand to be true from textbook discussions of synchronization
mechanisms, though, so I'm having trouble just dropping it.

So maybe one more comment, and a question.

The comment: I'm basing what I say not on the specifics of how
Java performs locking and unlocking -- which I admit I do not know
details of -- but on my understanding of synchronization mechanisms
and deadlocks in general, more or less as learned from textbooks on
operating systems.

The question: What's special about Java, such that order in which
locks are released doesn't matter, where it does in other languages /
APIs?
 
S

Stephen Kellett

The question: What's special about Java, such that order in which
locks are released doesn't matter, where it does in other languages /
APIs?

In Java you have no control over the 'release' part. You only control
the acquire. The release part is automatically handled by the scoping
rules of the language. This ensures that in Java the release order is
the reverse of the acquire order.

Or put another way, when you write the code in Java you are saying what
you want done (synchronization) but you are letting the compiler decide
how to implement it.

I've been trying to remember when these events happened in the hope I
could remember the scenario. It was about 3 or 4 years ago. I've been
involved in a lot of code since then. It doesn't surprise me that I
can't remember the scenario in any detail. If I can remember it I will
let you know. Or if I realise that I've conflated two separate but
related events I'll also let you know.

Stephen
 
S

Stefan Joubert

Stephen said:
Which is caused because you unlocked too early! This madness, you are
agreeing with me whilst disagreeing :). From what I have read in this
discussion if you don't believe the
release-in-reverse-order-to-acquisition rule you won't agree with the
rest of what I've written.

What rule is this? If lock 1 is guarding resource A then what
difference does it make when you release it relative to other locks
which are concurrently held? Isn't the real issue that of respecting
the locking hierarchy that is in effect?
 
B

blmblm

In Java you have no control over the 'release' part. You only control
the acquire. The release part is automatically handled by the scoping
rules of the language. This ensures that in Java the release order is
the reverse of the acquire order.

Oh, right, of course. Sorry -- I don't know what I was thinking,
asking that question.
Or put another way, when you write the code in Java you are saying what
you want done (synchronization) but you are letting the compiler decide
how to implement it.

I've been trying to remember when these events happened in the hope I
could remember the scenario. It was about 3 or 4 years ago. I've been
involved in a lot of code since then. It doesn't surprise me that I
can't remember the scenario in any detail. If I can remember it I will
let you know. Or if I realise that I've conflated two separate but
related events I'll also let you know.

Fair enough! I'm sure there are things about which I also could say
"you know, sometimes that goes wrong, but I can't remember the details
of the experience that taught me that ...."
 
S

Stephen Kellett

Stefan Joubert said:
What rule is this? If lock 1 is guarding resource A then what
difference does it make when you release it relative to other locks
which are concurrently held? Isn't the real issue that of respecting
the locking hierarchy that is in effect?

Please read the rest of the thread. We've come to dead halt on this
discussion.

Stephen
 
R

ricky.clarkson

Someone said that you could avoid multi-threading, but that this would
be undesirable if using networking.

I don't know whether you can do everything with java.nio that you can
with java.io, but surely that would solve that issue.

EIO - event-driven I/O [1] might also be a good way of doing things.

Effectively, using SwingUtilities.invokeLater and generally avoiding
threading by breaking things up into manageable chunks, you are
emulating threading. I don't know whether that's a good thing or a bad
thing, but I know I do it.

[1] http://java.twistedmatrix.com/eio/
 
S

Stefan Joubert

Stephen said:
Please read the rest of the thread. We've come to dead halt on this
discussion.

Stephen

I've read the entire thread. You are very confused about concurrency
issues as are most Java programmers I've encountered. You've come to a
dead halt like your software is likely to on a multiprocessor machine.
 
S

Stephen Kellett

Stefan Joubert said:
I've read the entire thread. You are very confused about concurrency
issues as are most Java programmers I've encountered. You've come to a
dead halt like your software is likely to on a multiprocessor machine.

If that is how you start your conversation I can only guess where it
will go. There is no point in continuing.

Stephen
 
S

Steve Horsley

Stephen said:
I'm not sure you understood what I meant - you may have, just your
comment "clean release" makes me unsure, as I am not talking about a
clean release. Two examples:

This is OK. (this is what I'd call a clean release if using that
terminology).

1.acquire.
2.acquire.
3.acquire.
3.release
2.release
1.release

This is not OK.

1.acquire.
2.acquire.
3.acquire.
2.release <- mistake.
1.release <- mistake
3.release <- mistake

At some point another thread will be able to acquire 1 and 2 out of
order with the acquisition of 3. This will lead to problems, most likely
with some other thread that is using some or all of these locks.

I haven't got time to write you a code example that dies, but I've seen
some pretty nasty results in Win32 multi-threading as a result of things
like this.

Stephen

My apologies for the long delay in replying after asking a question.

I have read the read of the thread (to date) and haven't seen
anything that persuades me that it is important to release in any
particular order. I have read once that as long as you acquire
locks in the same order (e.g. 1, 2, 3) there can be no deadlock,
and this makes sense to me. I can see that in a sequence such as:
1 acquire
2 acquire
3 acquire
2 release
2 acquire <= ERROR
the very last step is in error because it is acquiring 2 while it
already has 3. This is out of order and can deadlock with a
thread that wishes to acquire 2 and 3. But I really don't see any
harm in releasing in any order you like.

I guess the question is moot in a java thread, because, as was
pointed out, java's use of synchronised blocks and methods
enforces releasing in inverse order to locking because multiple
locks MUST be in nested blocks. Since the text I read about
acquiring locks in order was talking about java, there was no
need for it to discuss the release order, so I may be missing
some concept that is important for other languages.

Steve
 
S

Stephen Kellett

Steve Horsley said:
I have read the read of the thread (to date) and haven't seen anything
that persuades me that it is important to release in any particular
order.

I said in a previous post that I would followup if I remembered any
details and if in doing so I would also correct myself if I had
conflated any of my memories.

Your post reminded me of something and then a few hours later I had a
recollection of most of what my original posting. Hence this posting.
I have read once that as long as you acquire locks in the same order
(e.g. 1, 2, 3) there can be no deadlock,

Yes, I agree with this.
and this makes sense to me. I can see that in a sequence such as:
1 acquire
2 acquire
3 acquire
2 release
2 acquire <= ERROR
the very last step is in error because it is acquiring 2 while it
already has 3. This is out of order and can deadlock with a thread that
wishes to acquire 2 and 3.

This is what triggered my memory of events. We had been working on a
deadlock bug that involved recursive entry into a function that acquired
a lock. Someone had move a lock release to make it out-of-order (as I
have phrased it and as you show above if you can imagine your second
acquire happening inside the recursive function I mention) and weeks
later we had a deadlock bug that took some time to identify (and which
was as I said rather convoluted due to the recursive nature of events
and awkwardness of repeating the failure). The fix was to move the lock
release back to its rightful place and make any necessary adjustments.

At the time we realised that the code wouldn't have failed if the locks
involved in the original code and the recursive code had been released
in reverse order so this became a rule of thumb, which again in my mind
had turned itself into a hard and fast rule.

As you can see, as time passes both events merge and you have a
conflation of events.
But I really don't see any harm in releasing in any order you like.

Yes. I agree with this. This was my mistake. This won't affect
deadlocks. Releasing in any order may harm performance, depends upon
your app.
I guess the question is moot in a java thread, because, as was pointed

Yes, I dived in headfirst into a cow pat of my own making. Anyway, it
doesn't hurt to be honest about an honest failure of memory and it does
hurt not to correct any incorrect assertions thus made. I'm not sure if
you were the original poster I was chatting with as my newsreader has
expired all the posts. Anyway I hope that sets things straight.

Stephen
 
B

blmblm

In message <[email protected]>, Steve Horsley
<[email protected]> writes

[ snip ]
This is what triggered my memory of events. We had been working on a
deadlock bug that involved recursive entry into a function that acquired
a lock. Someone had move a lock release to make it out-of-order (as I
have phrased it and as you show above if you can imagine your second
acquire happening inside the recursive function I mention) and weeks
later we had a deadlock bug that took some time to identify (and which
was as I said rather convoluted due to the recursive nature of events
and awkwardness of repeating the failure). The fix was to move the lock
release back to its rightful place and make any necessary adjustments.

At the time we realised that the code wouldn't have failed if the locks
involved in the original code and the recursive code had been released
in reverse order so this became a rule of thumb, which again in my mind
had turned itself into a hard and fast rule.

As you can see, as time passes both events merge and you have a
conflation of events.


Yes. I agree with this. This was my mistake. This won't affect
deadlocks. Releasing in any order may harm performance, depends upon
your app.


Yes, I dived in headfirst into a cow pat of my own making. Anyway, it
doesn't hurt to be honest about an honest failure of memory and it does
hurt not to correct any incorrect assertions thus made. I'm not sure if
you were the original poster I was chatting with as my newsreader has
expired all the posts. Anyway I hope that sets things straight.

I'm one of the people you were chatting with earlier, and .... Oh,
this now makes much better sense. So would it be accurate to sum
up as "the real problem was that the code was acquiring locks in
the wrong order, but this was obscured by recursion and general code
complexity, and the easiest fix involved making it standard practice
to release locks in the opposite order in which they were acquired"?

That seems reasonable to me, and consistent with what I (think I) know
about synchronization mechanisms.

Glad we seem to have cleared this up!
 
S

Steve Horsley

I'm one of the people you were chatting with earlier, and .... Oh,
this now makes much better sense. So would it be accurate to sum
up as "the real problem was that the code was acquiring locks in
the wrong order, but this was obscured by recursion and general code
complexity, and the easiest fix involved making it standard practice
to release locks in the opposite order in which they were acquired"?

That seems reasonable to me, and consistent with what I (think I) know
about synchronization mechanisms.

Glad we seem to have cleared this up!

Yup.
And I have to agree, knowing the order that locks are taken in
can be very difficult. Java's nested blocks approach probably
helps simplify it quite a bit, because you can't just call an
acquire() function wherever you like.

Steve
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top