views:

497

answers:

5

Hi there!

Inside a for-loop I'm controlling the simulation-step-based traffic simulator SUMO by retrieving and processing information of vehicles. To make sure that my program simulates in "real-time" (1 simulation-step = 1 second) I want to sleep my program after the processing phase until the next time step begins. To get better results I'm calculating the time stamp based on a initially taken reference time stamp.

The loop looks like this:

 System.out.println("start of traffic simulation ...");

 for (int i = 0; i < stepCount; i++)
 {
  System.out.println("step: " + i);

  // set before timeStamp
  beforeTimeStamp = System.currentTimeMillis();

  if (firstStep)
  {
   // get reference timeStamp
   referenceTimeStamp = beforeTimeStamp;
   firstStep = false;
  }
  else
  {
   // get next vehicleVector
   vehicleVector = masterControl.traCIclient.simulateStep();
  }

        // process vehicleVector

  // set after timeStamp
  afterTimeStamp = System.currentTimeMillis();

  processingTime = afterTimeStamp - beforeTimeStamp;

  // calculate sleepTime
  sleepTime = referenceTimeStamp + ((i + 1) * 1000) - afterTimeStamp;

       // sleep for sleepTime ms
       Thread.sleep(sleepTime);
 }

 System.out.println("end of traffic simulation ...");

Here's the output of some variables:

step:   0                                                                                                         
beforeTimeStamp 1252317242565                                                                                   
reference time: 1252317242565                                                                                   
processing time: 394                                                                                            
test time: 1252317243565                                                                                        
afterTimeStamp 1252317242959                                                                                    
sleepTime: 606                                                                                                  
step: 1                                                                                                         
beforeTimeStamp 1252317242961                                                                                   
processing time: 665                                                                                            
test time: 1252317244565                                                                                        
afterTimeStamp 1252317243626                                                                                    
sleepTime: 939 (exspected: 1000 - 665 = 335)                                                                                                  

As you can see the sleep time is only correct for the first simulation step. I have no clue what might me going wrong here. Does anybody has an idea?

BR,

Markus

+10  A: 
oxbow_lakes
Isn't the simpler issue that he should be sleeping for (1000-processingtime), regardless of real-time issues ?
Brian Agnew
The 1000-processing time issue is a bug in the code. My answer is explanation as to why the whole approach is flawed, is a correct answer and I can't quite see how it's worthy of a downvote
oxbow_lakes
Well, I think the immediate question *is* where's the bug in the code. Following up with the issue that you can't do this reliably is worthwhile, however. Perhaps the downvote was too harsh. Removed.
Brian Agnew
@oxbow_lakes Do you know how the excecutor in your example behaves, if the execution of the task takes longer than a second? I'm not sure if I have to surround some parts of the code with synchronized-blocks to avoid that code is executed by several instances at once ...
Markus
@Markus - as the executor is single-threaded, it's not possible for it to be running multiple tasks at once. My (almost certainly correct) guess is that when scheduling at fixed rate, if the first invocation takes longer than the period, the next invocation will start immediately.
oxbow_lakes
@oxbow_lakes Do you have an idea how the ScheduledExecutorService internally works? Because I'm trying to compare some sleep variants within my master thesis this information would be very useful for me...
Markus
What do you want to know? Are you asking about the Java code or the `sun.misc.Unsafe` class? Why not ask another question on SO; it will be sure to be answered!
oxbow_lakes
+4  A: 

Why not sleep for 1000 - processingTime ? It would be the closest you can get to a correct answer.

Your solution only works on the first step because it's only correct for the first step. You assume that you will start your processing for each step at referenceTime + (step * 1000), but you are not taking overhead (thread sleeping, prints, garbage collection) into account. Print out referenceTimeStamp + ((i + 1) * 1000) - beforeTimeStamp to see what I mean

laura
+1 because I think it's the only answer that addresses the immediate bug in the code.
Brian Agnew
Mhhh, I'm not sure if 1000 - processingTime is what I really want to have, because in this case the sleep time is only based on the information of the last step. Using my solution I would be able to avoid some time drifting problems. But because I have no influence on the execution overhead, I probably have no other choice than using your solution ... or?
Markus
The only solution what actually comes closer to what you want is scheduleAtFixedRate in the other comments - the downside of which, if I understand your question correctly, is that you would not be sure that a step finishes before the next one begins (being run on different threads and all) - if that is not a problem, then a ScheduledExecutorService would ensure that each step begins 1000 millis after the previous one
laura
+2  A: 

As highlighted by others, you should be sleeping for 1000 - processing time.

Ignoring the fact that Java SE doesn't provide a real-time platform (and as such you won't get precision), I would perhaps take a look at the Timer class, and particularly Timer.scheduleAtFixedRate(), which will look after scheduling tasks at regular intervals.

Brian Agnew
+3  A: 

There is a simple standard solution in Java starting with Java 5.

Take a look at ScheduledExecutorService.

It will look something like this:

        ScheduledExecutorService service = Executors.newScheduledThreadPool(1);
        service.scheduleAtFixedRate(new MyCode(), 0, 1, TimeUnit.SECONDS);

Where MyCode class implements runnable interface and will be executed once a second.

This is not a real time guarantee but should be sufficient for your case.

Gregory Mostizky
A: 

Are you sure the output is from the same program? See the discrepancy highlighted inline,

step:   0                                                                                                         
beforeTimeStamp 1252317242565                                                                                   
reference time: 1252317242565                                                                                   
processing time: 394                                                                                            
test time: 1252317243565                                                                                        
afterTimeStamp 1252317242959                                                                                    
sleepTime: 606 #### It didn't sleep this long at all
step: 1                                                                                                         
beforeTimeStamp 1252317242961 #### This is only 2ms from last afteTimeStamp                                                                                 
processing time: 665                                                                                            
test time: 1252317244565                                                                                        
afterTimeStamp 1252317243626                                                                                    
sleepTime: 939 (exspected: 1000 - 665 = 335)  #### This is to make up the deficit from last sleep

There were 604 (606-2) deficit in fist sleep. So 939 (335 + 604) is the correct sleep time for second loop.

Java's sleep is not accurate but it can't be this far off. I think either you interrupt the program in a debugger or the code doesn't match the output.

ZZ Coder
Ohh, sorry. I forgot to mention, that I currently do NOT really sleep. Therefore the values are probably different from what you expected.
Markus