0

in my python project in got a timer that run "forever". here is the code for the timer :

class MyTimer: 
    def __init__(self, tempo, target, args= [], kwargs={}): 
        self._target = target 
        self._args = args 
        self._kwargs = kwargs 
        self._tempo = tempo 

    def _run(self): 
        self._timer = threading.Timer(self._tempo, self._run) 
        self._timer.start() 
        self._target(*self._args, **self._kwargs) 
        if globalVar.Flag_Stop_Timer==100:
            self._timer.cancel() 

    def start(self): 
        self._timer = threading.Timer(self._tempo, self._run) 
        self._timer.start() 

    def stop(self): 
        self._timer.cancel() 

the function that is called by the timer is doing readings in a PLC via the snap7 python "library"

The problem is that it seems that a thread is generate for each timer event. Because when i got 370 (it's repeatable) event i got the error :

Exception in thread Thread-370: Traceback (most recent call last):
File "/usr/lib/python2.7/threading.py", line 810, in __bootstrap_inner self.run() File "/usr/lib/python2.7/threading.py", line 1082, in run self.function(*self.args, **self.kwargs) File "Main.py", line 83, in _run self._timer.start() File "/usr/lib/python2.7/threading.py", line 745, in start _start_new_thread(self.__bootstrap, ()) error: can't start new thread

So my question is how can i be sure to fire a new timer event only if the previous event is finish? or something like that...

--------------FIRST EDIT -----------------

with the first comment from @J.F. Sebastian i use this :

def call_repeatedly(interval, func, *args):
    stopped = Event()
    def loop():
        while not stopped.wait(interval): # the first call is in `interval` secs
            func(*args)
    Thread(target=loop).start()    
    return stopped.set

Now everything seems to work well. For now it runs one hour without stopping. BUT although it didn't crash with the error i got before i got a strange behavior. Within 5 min of run the disconnect time take one more second than at start. As @ErikR said i start asking myself if snap7-python could be faulty I am making some test with no connect/disconnect each time.

got_fr
  • 39
  • 8
  • you don't need multiple threads, to call a function periodically without blocking your main thread. Here's a [code example that uses a single thread](http://stackoverflow.com/q/22498038/4279) – jfs May 14 '16 at 04:17

1 Answers1

0

Here is an approach which doesn't seem to leak any threads. Note - this does not create a new timer until the periodic action is complete.

#!/usr/bin/python

import time, threading

class MyPeriodic:
  def __init__(self):
    self.count = 0

  def start(self):
    self._timer = threading.Timer(1, self._run)
    self._timer.start()

  def stop(self):
    if self._timer:
      self._timer.cancel()
      self._timer = None

  def _run(self):
    self.stop()
    self.count += 1
    print "iteration:", self.count, "active:", threading.active_count(), "time:", time.ctime()
    self.start()
ErikR
  • 51,541
  • 9
  • 73
  • 124
  • thanks for your approach but i got the same result : ' iteration: 241 active: 2 time: Fri May 13 16:01:40 2016 FromEmit 1463155300.82 Exception in thread Thread-241: Traceback (most recent call last): File "/usr/lib/python2.7/threading.py", line 810, in __bootstrap_inner' – got_fr May 13 '16 at 16:04
  • Then there is a problem in the snap7 library or with the way you are using it. Perhaps the snap7 library is exhausting the system threads. Post the smallest example which exhibits the problem. – ErikR May 13 '16 at 16:38