views:

679

answers:

4

Hi guys,

I've got a little game that a friend and I are writing in Java. It's kind of badly coded and we're working on refactoring it, but that's not really the issue right now. We both have 64 bit machines and I guess before we were both using 32 bit JDKs, but recently I had some problems and so I removed all JDKs and installed the latest 64 bit JDK, and I'm not sure when but my friend is also now running a 64 bit JDK. Our game was running fine in the 32 bit JDK, but with the 64 bit version the game won't start. I've been trying to debug it with eclipse, but it's been a bit of a pain.

Our game is networked and multithreaded, and I think we have some issues with how we synchronized things (I didn't fully understand the whole idea of synchronization when I was writing it before) eg. we had made our run() methods synchronized which has no effect, but despite the stupidities of large parts of our code the stuff still runs on a 32 bit JVM (Windows and Linux).

The game starts up where one person hosts a game, and then others can join until the host decides to start the game. It then sends a prompt to all the players, asking if they want to start, and if all say yes the game starts. What is happening on the 64 bit JVM is that it sends the message, but it seems like the response is getting lost or something, or the server isn't counting correctly that everyone has OKed because the game doesn't actually start. Actually, the host gets a few more messages that the other player(s) don't get and gets a little farther in starting the game, but the server seems to get stuck somewhere.

Any ideas what might be the problem? Our code is up on github if anyone wants to take a look. I'd be extremely happy if you did, but I don't expect anyone to wade through our ugly code. Thanks!

By the way, we are both running on 64 bit Windows Vista and JDK 1.6 u12 and u14, but we also run Linux although I haven't been able to test it on a 64 bit Linux JVM yet. Oh, more details about why I'm pretty sure it's a 64 bit JVM isssue:

So we were working on this basically in the fall semester, and stopped working on it for a while. After 6 months we pick it up again, stagger at our horrid code, and start trying to clean it up. Then we realize that neither of us can run it properly. I try to find a revision that works, but I get to the last revision from before we started working on it this summer and it's still not working. I then even checked some binaries (.jars) that I had compiled before and even the earliest revision I have doesn't work on the 64 bit JVM. I then checked in a 32 bit Linux VM running the Sun JDK1.6 JVM, and it worked fine. Thus, I'm pretty sure it's a 64 bit problem since before the same binaries were working perfectly.

I've also noticed that Vista was assigning IPv6 addresses to my sockets for some reason, when connecting to a server on my own machine (0:0:0:0:0:1 instead of 127.0.0.1) but I fixed anything that was IPv4 specific and it's still not working.

I actually have just created another problem on my github repository which is a whole other tale of woe, so I can't test my latest build on another machine right now. But the last build before refactoring works fine on a 32 bit JVM with a dual core, so it doesn't look like a race condition.

Oh, another thing, exact same problem running under OpenJDK 6 64 bit under Linux. I'm guessing it's a race condition that the 64 bit version somehow brings out.

A: 

Are you running with the java process with the -d64 option? If not, then I'm pretty sure you're still running the JVM in 32-bit mode, and your issue may be related to the environment or the OS instead of the bitness.

Amir Afghani
I'm not, but I was under the impression that it would run in 64 bit mode by default. The fact remains that the program runs fine in the 32 bit JVM, so something else is amiss. I also need to add some details to my original post which make it more convincing that this is a 64 bit issue, but it really shouldn't be.
Ibrahim
It is actually fairly hard to detect whether you are using a 32-bit vs 64-bit JVM. They even perform much the same. It is more likely that there is a race condition you have which shows up on one JVM but not the other.
Peter Lawrey
+1  A: 

The game starts up where one person hosts a game, and then others can join until the host decides to start the game. It then sends a prompt to all the players, asking if they want to start, and if all say yes the game starts. What is happening on the 64 bit JVM is that it sends the message, but it seems like the response is getting lost or something, or the server isn't counting correctly that everyone has OKed because the game doesn't actually start. Actually, the host gets a few more messages that the other player(s) don't get and gets a little farther in starting the game, but the server seems to get stuck somewhere.

This sounds like it might be a race condition, i.e. flawed or missing synchronization. Since race conditions are timing-dependant, almost anything (including switching JVMs) can cause them to manifest.

I'd stop worrying about 64bit vs 32bit and try to diagnose the actual problem. Since it involves multiple machines, it's unfortunately going to be very hard (which is generally the case with race conditions).

The best way to do it is probably to make sure all machines have synchronized clocks using NTP, and then log the sending, receiving and processing of messages with millisecond timestamps so you can see where messages get lost or aren't processed properly.

Michael Borgwardt
Hmm, I thought it might be a race condition but I didn't realize that a different JVM could have different timing properties which would cause problems. I'm almost certain that I have incorrect synchronization, so I guess I'll have to overhaul a fair chunk of code.I have been trying to find an underlying problem, as I mentioned, but debugging multithreaded applications in eclipse is kind of a pain, and it runs fine in a 32 bit JVM. That's the only reason I asked about problems in the 64 bit JVM.
Ibrahim
Could it also be that your 32 bit machine was single core, and your 64 bit machine was multi-core? Multiple cores tend to increase the probability of underlying threading issues manifesting themselves. However, I agree that bitness is unlikely to be the underlying issue.
Nathan
A: 

I would not expect 64 vs. 32 to cause any issues in this case, threading is way more likely to be your cause

kudos for using raw sockets, but they're very tricky to get correct. Consider using a library for your network stack, like Apache Mina, unless of course the goal of the project is to write your own socket code. Definitely read over the quick start guide. It's text-based protocol maps directly to what you're using.

Side note: sticking synchronized on every method and using finalize are symptoms of bad things / code smells

basszero
Yeah, there is definitely a lot of bad code in there. I'm not sure what's so tricky about raw sockets? In any case, that's not the issue here. I'm pretty sure now that it is a race condition, but it's going to take a while to confirm it. I think in the mean time I will just go back to the 32 bit JVM since it works there.
Ibrahim
raw sockets are fine, but they are typically combined with threads which can easily to race conditions. My suggestion to use MINA will let you skip the networking stack and focus on writing an entertaining game!
basszero
A: 

We found out what the issue was. There was a loop in one part where a thread waited on something to become ready that another thread was working on, except it was just a while(!ready){} loop. It seems like in the 64 bit JVM threads don't get preempted or something, because in the 32 bit JVM this loop would get preempted and then the other thread would finish and set the variable to true, but not in the 64 bit JVM. I understand now that we should have used wait/notify and locks to do this, but at least temporarily throwing a sleep() in there fixed it. Not exactly a race condition, more of a quirk of the threading model it seems, so I'm not accepting any of the other answers since they didn't answer the question I asked.

Ibrahim
No, threads are always pre-empted. What is more likely is that your "ready" field was not volatile which means the JVM can cache the value and since you never change it in the local thread it doesn't see the change (or it will see it at some random point) i.e. don't busy wait on a value like this!
Peter Lawrey
Oh, ok. That makes more sense. Either way, the while loop is going out as I fix all the threading code. Most of the synchronization stuff is horribly wrong, because at the time I barely understood what synchronized did, and in some cases misunderstood. wait/notify is probably what I want to do here.
Ibrahim