# Copyright (c) 2011 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. import copy import threading import time class TimerQueue(threading.Thread): """Executes timers at a given interval. This class provides the ability to run methods at a given interval. All methods are fired synchronously. Only one method is running at a time. Example of using TimerQueue: def _fooPrinter(word): print('foo : %s' % word) timers = TimerQueue() timers.addTimer(self._fooPrinter, 15, args=('hello',)) timers.start() >> hello will be printed after 15 seconds Note: TimerQueue is a subclass of threading.Thread, call start() to activate; do not call run() directly. """ def __init__(self): """Initializes a TimerQueue object.""" threading.Thread.__init__(self, name='timer_thread') self.timer_queue_lock = threading.Lock() self.terminate = False self.wait_time = 1 self.timers = [] def AddTimer(self, method, interval, args=()): """Adds a timer to the queue. Args: method: the method to be called at the given interval interval: delay between method runs, in seconds args: arguments to be passed to the method """ self.timer_queue_lock.acquire() next_time = time.time() + interval self.timers.append({'method': method, 'interval': interval, 'next time': next_time, 'args': copy.copy(args)}) self.timer_queue_lock.release() def SetResolution(self, resolution): """Sets the timer check frequency, in seconds.""" self.wait_time = resolution def RemoveTimer(self, method): """Removes a timer from the queue. Args: method: the timer containing the given method to be removed """ self.timer_queue_lock.acquire() for timer in self.timers: if timer['method'] == method: self.timers.remove(timer) break self.timer_queue_lock.release() def Stop(self): """Stops the timer.""" self.terminate = True def run(self): """Primary run loop for the timer.""" while True: now = time.time() self.timer_queue_lock.acquire() for timer in self.timers: if timer['next time'] <= now: # Use * to break the list into separate arguments timer['method'](*timer['args']) timer['next time'] += timer['interval'] self.timer_queue_lock.release() if self.terminate: return time.sleep(self.wait_time)