Simple timer class

by Patrick Ruckstuhl (modified: 2007 Apr 19)

Sometimes in an application, some actions have to be repeatedly performed in a certain interval. This could for example be some cleanup of external data. To do this I wrote a small class that takes an agent and an interval. indexing description: "Execute an action every interval until stopped." author: "Patrick Ruckstuhl <patrick@tario.org>" date: "$Date$" revision: "$Revision$" class TIMER inherit THREAD export {NONE} all end create make feature {NONE} -- Initialization make (a_action: like action; a_interval: like interval) is -- Create a timer that executes a_action every a_interval milliseconds. require a_action_set: a_action /= Void a_interval_valid: a_interval > 0 do action := a_action interval := a_interval create timer_mutex.make create timer_condition.make ensure action_set: action = a_action interval_set: interval = a_interval end feature -- Status is_stop: BOOLEAN -- Is the timer stopped? feature -- Access action: PROCEDURE [ANY, TUPLE[]] -- Action to execute every interval. interval: INTEGER -- Milliseconds to wait until action is called again. feature -- Commands start is -- Start the timer. do is_stop := False launch end stop is -- Stop the timer. do is_stop := True timer_mutex.lock timer_condition.signal timer_mutex.unlock exit end feature {NONE} -- Implementation timer_mutex: MUTEX -- Mutex for timer. timer_condition: CONDITION_VARIABLE -- Condition variable to wait on during the interval. execute is -- Main loop, executes action every interval until stopped. local l_tmp: BOOLEAN do timer_mutex.lock from until is_stop loop action.call ([]) l_tmp := timer_condition.wait_with_timeout (timer_mutex, interval) end timer_mutex.unlock end invariant action_set: action /= Void interval_valid: interval > 0 timer_mutex_not_void: timer_mutex /= Void timer_condition_not_void: timer_condition /= Void end

On start, a new thread is created which executes a loop until is_stop is true. The waiting for the interval is done by using a CONDITION_VARIABLE which also allows to stop the execution at any moment, simply by signaling this CONDITION_VARIABLE after which, the loop condition is evaluated again, which ends the loop.

Sample usage of the class looks like this indexing description: "Sample" author: "Patrick Ruckstuhl <patrick@tario.org>" date: "$Date$" revision: "$Revision$" class SAMPLE create make feature {NONE} -- Initialization make is -- Create. local l_timer: TIMER do -- create a new timer, that print's hello worlds every 10 seconds create l_timer.make (agent print("Hello World%N"), 10*1000) l_timer.start end end

Comments
  • Jocelyn Fiat (9 years ago 30/11/2007)

    To see something, you might add a loop

    To see something, I would just add the following points:

    1) add THREAD_CONTROL to the inherited class for SAMPLE 2) at the end of make, you could add (for instance) from until False loop print (".") sleep (1_000_000_000) end

  • Philippe Laré (7 years ago 9/5/2010)

    How to stop it?

    How can the timer be stopped?

    The procedure stop has to lock the timer_mutex, which is already locked in the procedure execute. I tried on EiffelStudio 6.5 GPL with a short test and I had to remove the "timer_mutex.lock" and "timer_mutex.unlock" statements in the stop procedure to make it work.

    Perhaps am I missing something?

  • Larry Rix (6 years ago 11/1/2011)

    thread_capable: {PLATFORM}.is_thread_capable

    I am getting a precondition violation when attempting to use this code (see title).

    I have looked to see why I am getting this, but cannot immediately determine. Can someone assist?

    • Larry Rix (6 years ago 11/1/2011)

      Self Solved! Groovy! :-)

      So, answer was a combination:

      1. I needed to set the Concurrency to Eiffel Thread in the project settings.

      2. I needed to change the pre-compile from base to base-mt

      I then did a clean compile and ran. It got me to where I needed to be.

      Cheers!!