11

Say if I have four functions as below:

def foo():
    subprocess.Popen('start /B someprogramA.exe', shell=True)

def bar():
    subprocess.Popen('start /B someprogramB.exe', shell=True)

def foo_kill():
    subprocess.Popen('taskkill /IM someprogramA.exe')

def bar_kill():
    subprocess.Popen('taskkill /IM someprogramB.exe')

How can I alternate foo and bar functions to run every, say 30 minutes? Meaning: 1st 30mins - run foo, 2nd 30mins - run bar, 3rd 30mins - run foo, and so on. Each new run should 'kill' the previous thread/func.

I have a countdown timer threads, but not sure how to 'alternate' the functions.

class Timer(threading.Thread):
    def __init__(self, minutes):
        self.runTime = minutes
        threading.Thread.__init__(self)


class CountDownTimer(Timer):
    def run(self):
        counter = self.runTime
        for sec in range(self.runTime):
            #do something           
            time.sleep(60) #editted from 1800 to 60 - sleeps for a minute
            counter -= 1

timeout=30
c=CountDownTimer(timeout)
c.start()

EDIT: My solution with Nicholas Knight's inputs...

import threading
import subprocess
import time

timeout=2 #alternate delay gap in minutes

def foo():
    subprocess.Popen('start /B notepad.exe', shell=True)

def bar():
    subprocess.Popen('start /B calc.exe', shell=True)

def foo_kill():
    subprocess.Popen('taskkill /IM notepad.exe')

def bar_kill():
    subprocess.Popen('taskkill /IM calc.exe')


class Alternator(threading.Thread):
    def __init__(self, timeout):
        self.delay_mins = timeout 
        self.functions = [(foo, foo_kill), (bar, bar_kill)]
        threading.Thread.__init__(self)

    def run(self):
        while True:
            for f, kf in self.functions:
                f()
                time.sleep(self.delay_mins*60)
                kf()

a=Alternator(timeout)
a.start()

Works fine.

siva
  • 2,105
  • 4
  • 20
  • 37

4 Answers4

10

Remember that functions are first-class objects in Python. That means you can store them in variables and containers! One way to do it would be:

funcs = [(foo, foo_kill), (bar, bar_kill)]

def run(self):
    counter = self.runTime
    for sec in range(self.runTime):
        runner, killer = funcs[counter % 2]    # the index alternates between 0 and 1
        runner()    # do something
        time.sleep(1800)
        killer()    # kill something
        counter -= 1
Santa
  • 11,381
  • 8
  • 51
  • 64
6

You're overcomplicating this.

while True:
    foo()
    time.sleep(1800)
    foo_kill()
    bar()
    time.sleep(1800)
    bar_kill()

Or if you want to easily add more functions later:

functions = [(foo, foo_kill), (bar, bar_kill), ] # Just append more as needed
while True:
    for f, kf in functions:
        f()
        time.sleep(1800)
        kf()
Nicholas Knight
  • 15,774
  • 5
  • 45
  • 57
  • running outside a thread would limit other codes from executing? – siva May 24 '11 at 03:06
  • @siva: To be clear, I wasn't intending "don't run it in a separate thread", I just meant that you were overcomplicating what was in the thread. Wrapping it in a function and launching it in a thread as you've done is fine. – Nicholas Knight May 24 '11 at 19:52
2

Use a variable to record which function you ran last time. When the timer fires, run the other function and update the variable.

LaC
  • 12,624
  • 5
  • 39
  • 38
1
import itertools, time

# make sure the function are in the order you want to run them in
# and grouped by the ones that you want to run together
funcs = ((bar_kill, foo), (foo_kill, foo)) 

for func_killer, func in itertools.cycle(funcs)
    func_killer()
    func()
    time.sleep(30 * 60) # pause for 30 minutes

function can be stored in lists in pythons, and you can iterate them using a for loop.

itertools is a module to manipulate iterable such as lists. Here we use cycle to make an infinit loop that will process the functions in the list funcs over and over.

Bite code
  • 578,959
  • 113
  • 301
  • 329