Java-Gaming.org Hi !
Featured games (83)
games approved by the League of Dukes
Games in Showcase (525)
Games in Android Showcase (127)
games submitted by our members
Games in WIP (592)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: 1 2 [3]
  ignore  |  Print  
  Impossible race condition between threads?  (Read 9963 times)
0 Members and 1 Guest are viewing this topic.
Online Roquen
« Reply #60 - Posted 2013-11-03 12:52:54 »

Those links are unrelated to what I'm saying.  The new JMM requires (for example) all non-violate writes to be made visible to main memory when a volatile write occurs and the volatile write is a memory-barrier for the compiler.  You need to know what you're doing to play these kinds of games and even if you do I'd suggest avoiding.
Offline nsigma
« Reply #61 - Posted 2013-11-03 13:57:12 »

Those links are unrelated to what I'm saying.

Huh?

Remember we're talking about the compiler seeing the value of a field as being constant across the lifetime of a method ...  The compiler is performing a perfectly legal transformation which doesn't consult main-memory.

Those links are exactly about the fact that this is an illegal transformation in this case, because the compiler isn't allowed to assume the value as constant given the crossing of a memory barrier with another thread that is changing the value.

The new JMM requires (for example) all non-violate writes to be made visible to main memory when a volatile write occurs and the volatile write is a memory-barrier for the compiler.

Absolutely, and you can't have the JIT compiler caching values without regard to this, or the JMM is pointless - again the subject of those links.

You need to know what you're doing to play these kinds of games and even if you do I'd suggest avoiding.

Definitely!  I said the same earlier.  No (or being realistic, minimal) shared state is definitely my preference.

Praxis LIVE - open-source intermedia toolkit and live interactive visual editor
Digital Prisoners - interactive spaces and projections
Offline theagentd

« JGO Bitwise Duke »


Medals: 361
Projects: 2
Exp: 8 years



« Reply #62 - Posted 2013-11-03 14:14:05 »

Thanks for the hints! Does this test deadlock for you as well? http://www.java-gaming.org/?action=pastebin&id=754

I can't explain it either, but using ArrayBlockingQueue(1) instead of using SynchronousQueue got rid of the deadlock

SynchronousQueue would be more accurately equivalent to ArrayBlockingQueue(0)!  ie., it has no storage at all.

The issue is the use of offer() vs put() - non-blocking vs blocking.  Check the return value of offer() and it should be false.  The offer() in Thread 1 does not block and cannot return successfully unless Thread 2 is already in the take() method, and then Thread 1 blocks on a take() that can never be serviced.  Thread 2 is doing the reverse, hence deadlock.

The use of an ArrayBlockingQueue with a single storage slot would allow offer() to work.
Ugh... Of course. Can't code at 5 in the morning...


hmm .. I fail to see how localvar promotion in that case wouldn't break the Java Memory Model.  Any localvar caching should be invalidated by crossing the memory barrier or that would appear to be a bug?

It doesn't surprise me that this short example is working.  I still believe the bug in the original code is elsewhere (probably in the signalling of task completion) and you're chasing the rabbit down the wrong hole!  Wink

The question then would be, why does the bug go away when counting backwards? A bug elsewhere (e.g. calling run(TaskTree) before the current batch of tasks has completed) would still be problematic in that case. Making totalTasks volatile would also make no difference. Btw, theagentd, have you actually tried that with the original code?

That's exactly what I did to solve it. I set the atomic counter to taskTree.getNumTasks() directly instead of even having a totalTasks variable, decremented the value by 1 and compared it to 0. I have not encountered the problem after that.


Remember we're talking about the compiler seeing the value of a field as being constant across the lifetime of a method ...  The compiler is performing a perfectly legal transformation which doesn't consult main-memory.

Those links are exactly about the fact that this is an illegal transformation in this case, because the compiler isn't allowed to assume the value as constant given the crossing of a memory barrier with another thread that is changing the value.

The new JMM requires (for example) all non-violate writes to be made visible to main memory when a volatile write occurs and the volatile write is a memory-barrier for the compiler.

Absolutely, and you can't have the JIT compiler caching values without regard to this, or the JMM is pointless - again the subject of those links.
This is exactly what I think as well. The bug does seem to be "closed" however?

Myomyomyo.
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Spasi
« Reply #63 - Posted 2013-11-03 15:35:55 »

That's exactly what I did to solve it. I set the atomic counter to taskTree.getNumTasks() directly instead of even having a totalTasks variable, decremented the value by 1 and compared it to 0. I have not encountered the problem after that.

I know. I meant only add volatile to totalTasks and change nothing else.

This is exactly what I think as well. The bug does seem to be "closed" however?

It was fixed in 7u6 and only affected the client JVM. On what version are you testing?
Offline theagentd

« JGO Bitwise Duke »


Medals: 361
Projects: 2
Exp: 8 years



« Reply #64 - Posted 2013-11-03 15:45:53 »

That's exactly what I did to solve it. I set the atomic counter to taskTree.getNumTasks() directly instead of even having a totalTasks variable, decremented the value by 1 and compared it to 0. I have not encountered the problem after that.
I know. I meant only add volatile to totalTasks and change nothing else.
Ah, I see. I did not test that since my fix was working. ._.

This is exactly what I think as well. The bug does seem to be "closed" however?

It was fixed in 7u6 and only affected the client JVM. On what version are you testing?
I was running on 7u25, but I've just now updated to 7u45. I have no idea how I was using such an outdated version...


EDIT: Wait, can we be sure that the fix for volatile fields can be applied to the concurrent collections? Maybe that's already covered somewhere else but not working?
EDIT2: This bug was "backported" (?) in 7u45: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=8018259

Myomyomyo.
Offline theagentd

« JGO Bitwise Duke »


Medals: 361
Projects: 2
Exp: 8 years



« Reply #65 - Posted 2013-11-03 16:48:53 »

Hmm... I don't think there's much more I can do anymore since I haven't been able to reproduce the original problem for a while. The best I can do is probably to revert the fix I used so the code looks identical to before and see if the error comes back with my current Java version. Unless someone has anything to add I feel pretty satisfied for now at least.

With that said, I'd like to thank everyone here so much for this very interesting discussion!

Myomyomyo.
Online Roquen
« Reply #66 - Posted 2013-11-05 10:51:20 »

Those links are exactly about the fact that this is an illegal transformation in this case, because the compiler isn't allowed to assume the value as constant given the crossing of a memory barrier with another thread that is changing the value.
One of us is misreading the specification.  The linked example has a load-fence (in the method) prior to reading the non-volatile field which tells the compiler that it cannot perform certain transforms (including that it must re-read main-memory) and (probably) must emit some CPU specific instruction(s) to insure memory is consistent.  The first snippet in this thread does not contain a barrier.  The fact that it calls a method which contains a barrier (in my reading of the spec) is irrelevant.  If my reading is incorrect that means that java is very limited in the set of transformation that it can apply because it must "prove" that no called function contains a load-fence/store-fence or full barrier.  Generally this is difficult to impossible (consider for instance JNI calls). More importantly such a specification wouldn't (IMHO) serve a useful purpose and would make implementing the compiler & de-compiler a massive headache.

Even if my reading is incorrect the variable still should be defined volatile so the code's intent is clear both to the compiler and anyone reading the code in the future (including the author at some point in the future).

(EDIT: funny typo)
Offline nsigma
« Reply #67 - Posted 2013-11-05 12:12:29 »

The fact that it calls a method which contains a barrier ... is irreverent. 

Ah, if only that misprint was what you meant!  Wink  "Damn, fool, don't you be dissing me by calling no methods"  Grin

If my reading is incorrect that means that java is very limited in the set of transformation that it can apply because it must "prove" that no called function contains a load-fence/store-fence or full barrier.

If it first inlined the method call(s), surely that wouldn't be that difficult?  btw - even if this was single threaded, it would have to prove that no method call changed the inlined value!

Even if my reading is incorrect the variable still should be defined volatile so the code's intent is clear both to the compiler and anyone reading the code in the future (including the author at some point in the future).

Absolutely!  In fact, as I said earlier I reckon the bug at the start of this thread is probably due to improperly paired lock calls, which would explain the simpler test case working OK, and a good reason for making intent clear.

The JVM bug linked to earlier, or rather the thread about it, does highlight that there aren't (weren't?) good test cases for the memory model in code output by the JIT compiler.  Another reason not to trust edges cases in the JMM too much!  Smiley

Praxis LIVE - open-source intermedia toolkit and live interactive visual editor
Digital Prisoners - interactive spaces and projections
Pages: 1 2 [3]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

toopeicgaming1999 (67 views)
2014-11-26 15:22:04

toopeicgaming1999 (58 views)
2014-11-26 15:20:36

toopeicgaming1999 (12 views)
2014-11-26 15:20:08

SHC (24 views)
2014-11-25 12:00:59

SHC (24 views)
2014-11-25 11:53:45

Norakomi (29 views)
2014-11-25 11:26:43

Gibbo3771 (24 views)
2014-11-24 19:59:16

trollwarrior1 (37 views)
2014-11-22 12:13:56

xFryIx (76 views)
2014-11-13 12:34:49

digdugdiggy (53 views)
2014-11-12 21:11:50
Understanding relations between setOrigin, setScale and setPosition in libGdx
by mbabuskov
2014-10-09 22:35:00

Definite guide to supporting multiple device resolutions on Android (2014)
by mbabuskov
2014-10-02 22:36:02

List of Learning Resources
by Longor1996
2014-08-16 10:40:00

List of Learning Resources
by SilverTiger
2014-08-05 19:33:27

Resources for WIP games
by CogWheelz
2014-08-01 16:20:17

Resources for WIP games
by CogWheelz
2014-08-01 16:19:50

List of Learning Resources
by SilverTiger
2014-07-31 16:29:50

List of Learning Resources
by SilverTiger
2014-07-31 16:26:06
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!