Lab-5538: The Real-Time Java™ Platform Programming Challenge: Taming Timing Troubles

Expected Duration: 120 minutes

Exercise 3: Real-Time Data Communication (almost!)

Expected duration: 20 minutes — 5 minute introduction then 15 minutes for lab

The goal of this exercise is to learn how to use a timer and asynchronous event handler to gather data and communicate it to non-real-time parts of the system using a data communication channel that is supplied. In addition you will find (once again) that meeting your real-time requirements takes additional considerations in the code you use. The requirements are:

  • Create a PeriodicTimer set to fire every 50ms.
  • Associate with that timer a non-heap-using instance of AsyncEventHandler that, on each release, reads data from a "sensor" and pushes that data into an instance of the supplied DataBuffer data communication channel.
Warning: Threads with real-time priorities run to the exclusion of all non-realtime processes on the system, including operating system services, shells and GUIs! If your real-time thread does not explicitly block it will consume 100% of a CPU. If you have less CPUs than real-time threads doing this then you system may appear to lock-up. So take care with experimentation: an infinite loop may require a reboot to fix!

Background Information

 

Read the material in the presentation, up to the slide titled "Exercise 3".

  • You've already seen how to create a periodic real-time thread in Exercise 1. Using a PeriodicTimer with an associated AsyncEventHandler is another way of expressing a periodic activity. The choice between them is often a matter of style, but if you need to pause your periodic activity, or to change the timing of it, then a timer has these capabilities built-in, while you would have to code them from scratch for a real-time thread.
  • A no-heap AsyncEventHandler is created by passing a constructor argument (in contrast to threads where NoHeapRealtimeThread is a subclass of RealtimeThread). Ensure you set its priority to be greater than the RTGC!
  • Give the handler periodic release parameters to reflect its periodic nature.
  • On each release (that is on each firing of the timer) the AsyncEventHandler will be associated with a real-time thread supplied by the system, and that thread will execute the handler's handleAsyncEvent method. This method contains the code that you want to be executed every 50ms. In contrast to the periodic real-time thread, you do not have to write a loop that calls a special method to block until the next release — the asynchronous event handling mechanism takes care of that for you.
  • We're concerned about not missing deadlines — which means that the handler must complete execution of its handleAsyncEvent method before the next release. While the handler could have its own deadline-miss handler installed, a simpler technique is to check the handler's pending release count: if this count is greater than zero then a deadline has been missed because another release is pending. Place the following code at the start of your handleAsyncEvent method to report deadline misses:
            int pending = getAndClearPendingFireCount();
            if (pending > 0) {
                throw new Error("Deadline missed! - pending count " + pending);
            }
  • Your event handler is emulating a periodic activity that reads data from a device (an instance of Sensor in this example) and pushes that data to a communication channel (an instance of DataBuffer). In this exercise the data is unimportant and a simple double value will be used. Data is read from a Sensor using the read() method, and is pushed to the DataBuffer using the add(double d) method. The internal details of DataBuffer are not a concern in this exercise — but will be in the next!
  • The data is extracted from the channel using a non-realtime consumer thread (an instance of ConsumerThread), and the data is "processed" prior to extraction. This consumer thread is setup for you by the Main program.
  • Terminate the application by having your handler invoke System.exit(0); when it runs for the 100th time.
  • To avoid unpredictable delays due to class-loading we're utilizing the Initialization Time Compilation (ITC) feature of Sun Java RTS. This is handled by the settings defined under Project Properties -> Real-Time Configuration. The use of ITC should be transparent to you for the purposes of these exercises, but you may see messages in the console output referring to the files itc.precompile and/or itc.preinit — these files have been provided for you in each of the project directories.

Steps to Follow

 
  1. Start the Netbeans IDE if not already started. There are projects defined for each exercise and its solution. Expand the project Ex3 by clicking on the "lollypop" icon to the far left of the project name, in the project pane. Click on the same icon next to the Source Packages item to show the packages defined in this project. Click on the same icon next to the ex3 package name to show all the source files defined in this project. To edit a source file, double-click on its name and an editing tab for that file will appear in the right-hand pane.
  2. Edit the PeriodicAEH class (in PeriodicAEH.java) and fill in the logic of the handleAsyncEvent() method, as indicated, to:
    • Check for and report deadline misses
    • Read a data value from the sensor and add it to the data buffer. Print each value to the console so that you can see that the handler is executing.
    • Terminate the application on the 100th release of the handler.
  3. Edit the Main class (in Main.java) and add code, as indicated, to the main method to:
    • Enable creation of an instance of the PeriodicAEH class with a period of 50ms. You must create suitable PriorityParameters and PeriodicParameters objects to pass to the PeriodicAEH constructor — similarly to what you did for Exercise 1.
    • Create a PeriodicTimer, with an interval of 50ms, an immediate start time, and associated with your PeriodicAEH handler.

    The main method contains code to start your timer. It also contains the code to construct and start an instance of ConsumerThread, but initially the starting of the consumer thread is commented out to allow testing of the handler in isolation.

  4. Build the project by right-clicking on the project name in the project pane, and then clicking on Build. Correct any compilation errors and build again, repeating as necessary.
  5. Run the project:
    • From within Netbeans by right-clicking on the project name in the project pane, and then clicking on Run. The output will be displayed in the output pane at the bottom of the window.
    • From a terminal window by executing the command: <INSTALL_DIR>/bin/java -jar /export/home/lab5538/realtimejava/exercises/Ex3/dist/Ex3.jar
    Here's an example of part of what you might see:
    # > /opt/SUNWrtjv/bin/java -jar /export/home/lab5538/realtimejava/exercises/Ex3/dist/Ex3.jar
    Application started ...
    Handler read 0.838178
    Handler read 0.509115
    Handler read 0.769864
    
  6. Note: the application will attempt to terminate after 60 seconds, in case your event handler does not terminate when it should.

  7. When you're satisfied with the operation of your handler, uncomment the line in the main method that starts the consumer thread. Re-build and re-run your application.

    Did your application complete successfully? Or did you see an exception like the following?

    java.lang.Error: Deadline missed! - pending count 14
            at ex3.PeriodicAEH.handleAsyncEvent(PeriodicAEH.java:43)
            at javax.realtime.AsyncEventHandler.run1(AsyncEventHandler.java:855)
    
    If you did, you won't be alone — there's something interfering with the timely execution of our periodic event handler — and this time we know it isn't the GC! — and in the next exercise you'll find out what it is this time.

Solution

 

The solution of this exercise is provided as a "ready to build and run" NetBeans project: <lab_root>/realtimejava/solutions/exercise3/Ex3Soln.


Summary

 

In this exercise, you learned how to create a periodic timer to release an event handler, and how to create an event handler to respond to events — both fundamental building block in many real-time systems. You also learned how to create a simple producer/consumer architecture to communicate data between the real-time and non-real-time parts of the system — but as with Exercise 1 you've seen that meeting deadlines isn't always straight-forward.

 

Back to top
Next exercise