eiffelroom

articleSimple timer class

patrickr's picture

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

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

about - contact