There are several issues to consider when using threads in Robocode:
Bots using multithreading:
If anyone has aditional information about threads, please add it.
-- Albert
I didn't manage to find the original thread but this one where DavidAlves tell us :"Threads. Actually I'm not sure I'd ever want thread support to be added, since Paul Evans pointed out the possibility of writing malicious threads that only execute during your opponent's turn in order to cause your opponent to skip turns." in a discussion about robocode 2. Someone as more info ? -- Synnalagma
Processing time in threads does not count towards the time limit per tick, and threads are not halted during the enemy's turn. So it would be possible (but not ethical) to slow down the processor during the other bots' turn to make them skip turns. -- ABC
If you use threads in your robot, you MUST spawn those threads from within your main Robot class. Calling threadName.start() from anywhere but your main Robot class will result in a rather nasty SecurityManager? exception, something like "java.security.AccessControlException?: Preventing package.class from access to threadgroup: Robot Loader Group". Don't forget to also stop all your threads from within onDeath() and onWin() or else Robocode will not give you a score, so the IBM forums tell me. There is also apparently a limit of 5 threads per robot. -- Nathanael
Is there a simple code sniplet to demonstrate multitreading? thx --SSO
Here's a simple thread I made to help me figure out some sample botcode I got from this wiki. It's implemented as an inner class inside the main bot class - this is convenient because inner classes can use the properties and methods of the enclosing class.
private class Logger extends Thread {
/** * Thread which logs the number of times the bot changes direction * Each change is accumulated into mainclass property "directionChangesCount?" by the move code */ public void run() {
do { logToConsole?( "Ticks: " + getTime() + " Dir changes: " + getDirectionChangesCount?() ) ; try { Thread.sleep( 1000 ) ; // milliseconds } catch (InterruptedException? e) {} // no need to react to an interrupt } while ( isLogThreadSemaphore?() ) ;
logToConsole?( "Leaving Logger.run()" ) ; logToConsole?( "Ticks: " + getTime() + " Dir changes: " + getDirectionChangesCount?() ) ;
}
}
Here's the code to start the thread (called during initialization, from the run() method of the bot):
// // Start status logging. The thread and the semaphore are properties of the main class, with // accessor methods. // setLogThread( new Logger() ) ; setLogThreadSemaphore?( true ) ; getLogThread().start() ;
And the stop code (also needed in onWin()):
public void onDeath( DeathEvent? e ) { setLogThreadSemaphore?( false ) ; }
Notes about threads (in case anyone cares):
Nice writeup ycn228 but a few comments anyway :)
To answer "Why use threads in Robocode?" I would say that some algorithm can take too much time if processed in the main thread. The segmentation tree in Toad takes about 175 ticks at the end of a 35 rounds game. So without threads I could not do it. I only use one mutex to avoid inserting leaves, when rebuilding. -- Florent
Sounds like a good case for threads. Not too easy to rebuild such a structure asynchronously though, definatley only for the more advanced and thread-experienced. -- Pulsar
You might be right about threading in Robocode Pulsar. I prefer the code structure you get with threading, but I've learned that I can't "stack" a sequence of calls to the same setXX methods (like several calls for turning the radar), and I think that means handling the radar, movement, and turret in separate threads would be more trouble with threading rather than less. Florent's situation is different of course. BTW - just to be picky :) my semaphore is a static field in the enclosing class, so it works like a volatile variable in the thread class. When I first learned thread coding in Java many JVMs didn't actually implement "volatile", so the normal practice was to code your own. That was Java 1.1.8 to 1.3.1 though - I guess the standard of JVMs has improved since then? Anyway if no-one else does it, I'll add a writeup on how to handle shared data and signalling between threads later on, but I want to check out the new 1.5 features first, because it's all such a PITA with the pre-1.5.implementation. -- ycn228
Now that you need to clarify for me. Yes you are right about the volatile field not being implemented correctly in old JVMs. I've been coding in java since -96 and the then new java 1.0. Furthermore it isn't until the new memory model with JSR 133 (partly fixed in java 1.4 and more so in 1.5) that the specification was updated to remove certain problems with synchronization, volatile being one of them as well, which I hope you are aware of. For example volatile variables, such as a declared volatile boolean, could not be used to mark something as initilized or similar where you needed other stuff to have been set (the order of volatile reads and writes were ok, but not other instructions around them). Florent could not use it for example to mark the tree as updated. But on to the question at hand:
I have a problem with this statement: "my semaphore is a static field in the enclosing class, so it works like a volatile variable in the thread class".
First of all, looking at the example code the use of semaphore here in thread terms is a bit misleading, but a semaphore can be a flag I guess in general terms. But in threading it is better to avoid misunderstandings and only use the word for what is in the common usage there, meaning a type of aquire and release lock, which it is not in your example above.
The second thing is that by delcaring the field static (and maybe along with as it is an "enclosing class") would somehow magically make the variable volatile? Maybe I'm missing something (very possible), but I don't think so. The JLS is very clear about references (read or writes) to variables from different threads, including static variables. They need to be volatile or otherwise thread synchronized to get a consistent view at any one time. Class variables (static) are part of the threads own memory view. By the way classes can be "synchronized on" too to synchronize the view of static variables.
The workaround for volatile fields was to use the monitors (synchronized) instead. -- Pulsar
Interesting comments Pulsar - to be honest I've never tried to study Java threads at the level you are describing them, for two reasons:
I've always assumed that this means the thread tests the boolean in the main class directly, which is why I said it has the same effect as declaring the field volatile. I've never tried to check that it really happens this way. There's still nothing stopping other threads from updating at the same time as I'm reading, but since it's just a boolean controlling a short timer loop, and there is no code anywhere which can change the signal from "stop" back to "start" it doesn't actually matter. The worst that can happen is that I loop once more before shutting down. This just means that it works ok in this situation though - I agree that it's not actually protected from possible weird side effects of unsynchronized updates.
Bottom line for me is that I'll take a good look at the new Java 1.5 features RSN. IIRC there are fields which can't be accessed by more than one thread at a time, and also better ways to start/stop threads. You can expect a lot of questions from me immediately after I read up on 1.5 :-)
-- ycn228
Ok just one more thing then: "The worst that can happen is that I loop once more before shutting down." Actually it is never explicitly guaranteed to stop. In practice that will never happen but it sure can cause more than one extra loop. Threads all have their own view of the memory in java for performance reasons, a very good thing. But this means that the robocode threads and your thread both have their own copy of the flag. To make sure that the threads' view of what the variable actually contain are the same you neeed to synchronize those threads (see were that keyword in java is coming from now?). Synchronizing on the same object (monitor) makes sure that the view of those threads synchronizing have the same view of the state of variables (at that time). Variables declared volatile are required to be read and written directly to the "master"/main memory so that all threads are forced to have the same view always: This also incurs a, usually small, performance hit.-- Pulsar
Toad is certainly on the slow side, but on my MacBook, it still runs at quite a reasonable speed - a 35 round battle takes about a minute or less. However, on my Linux machine (running Ubuntu), which is generally 1/2 to 2/3 the speed of my MacBook for Robocode, it runs at about 10 FPS. It's running Sun Java 1.5. Anyone have some insight about this? (It basically means Robocode hangs forever if the RR@Home client on that machine catches a Toad battle, and I have to just restart it once I catch it.) -- Voidious
Just reading part of this page, shows me I should leave the threads to those who won't cause robocode and java itself to shutter to a halt by using them. Thought it was a nice idea on how to impliment the massively slow k-type clustering and some neural-netowrks, which don't necessarily need to be syncronized. However the complications of that, are more then I can probably figure out. --Chase-san