diff --git a/Doc/library/threading.rst b/Doc/library/threading.rst index 2792dfdce04c6c..210a450462f371 100644 --- a/Doc/library/threading.rst +++ b/Doc/library/threading.rst @@ -831,29 +831,39 @@ method. The :meth:`~Event.wait` method blocks until the flag is true. Timer Objects ------------- -This class represents an action that should be run only after a certain amount -of time has passed --- a timer. :class:`Timer` is a subclass of :class:`Thread` +This class represents an action that should be run after a certain amount +of time has passed --- a timer. It also can run periodically. Each run takes +place after a specified time after the previous run. This continues until +the action returns TRUE. :class:`Timer` is a subclass of :class:`Thread` and as such also functions as an example of creating custom threads. Timers are started, as with threads, by calling their :meth:`~Timer.start` method. The timer can be stopped (before its action has begun) by calling the -:meth:`~Timer.cancel` method. The interval the timer will wait before -executing its action may not be exactly the same as the interval specified by -the user. +:meth:`~Timer.cancel` method. If action has returned True then next run is +scheduled after the timer interval. The interval the timer will wait before +executing its action may not be exactly the same as the interval specified +by the user. + For example:: - def hello(): - print("hello, world") + def star(): + global cnt + print("*") + cnt -= 1 + if cnt > 0: + return True - t = Timer(30.0, hello) - t.start() # after 30 seconds, "hello, world" will be printed + cnt = 5 + t = Timer(1.0, star) + t.start() # it prints five "*" with 1 sec waiting between prints .. class:: Timer(interval, function, args=None, kwargs=None) Create a timer that will run *function* with arguments *args* and keyword - arguments *kwargs*, after *interval* seconds have passed. + arguments *kwargs*, after *interval* seconds have passed and continues + periodically run *function* till *function* returns True. If *args* is ``None`` (the default) then an empty list will be used. If *kwargs* is ``None`` (the default) then an empty dict will be used. diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py index 2c2914fd6d8969..e95f64df772492 100644 --- a/Lib/test/test_threading.py +++ b/Lib/test/test_threading.py @@ -1067,6 +1067,7 @@ class TimerTests(BaseTestCase): def setUp(self): BaseTestCase.setUp(self) self.callback_args = [] + self.callback_cnt = 3 self.callback_event = threading.Event() def test_init_immutable_default_args(self): @@ -1087,6 +1088,29 @@ def test_init_immutable_default_args(self): def _callback_spy(self, *args, **kwargs): self.callback_args.append((args[:], kwargs.copy())) self.callback_event.set() + self.assertEqual(self.callback_event.is_set(), True) + + def test_continuous_execution(self): + timer1 = threading.Timer(0.01, self._callback_cont) + self.callback_event.clear() + timer1.start() + for i in range(3): + self.callback_event.wait(1.0) + self.callback_event.clear() + self.assertEqual(self.callback_cnt, 0) + self.callback_cnt = 3 + timer2 = threading.Timer(0.5, self._callback_cont) + self.callback_event.clear() + timer2.start() + timer2.cancel() + timer2.join(2.0) + self.assertEqual(self.callback_cnt, 3) + + def _callback_cont(self): + self.callback_cnt -= 1 + self.callback_event.set() + self.assertEqual(self.callback_event.is_set(), True) + return self.callback_cnt > 0 class LockTests(lock_tests.LockTests): locktype = staticmethod(threading.Lock) diff --git a/Lib/threading.py b/Lib/threading.py index 4829ff426e0bfd..1b639f6862941d 100644 --- a/Lib/threading.py +++ b/Lib/threading.py @@ -1177,9 +1177,10 @@ def cancel(self): self.finished.set() def run(self): - self.finished.wait(self.interval) - if not self.finished.is_set(): - self.function(*self.args, **self.kwargs) + """Continue execution after wait till function returns True""" + while(not self.finished.wait(self.interval)): + if not self.function(*self.args, **self.kwargs): + break self.finished.set() # Special thread class to represent the main thread