pk10
pk10

Reputation: 523

How to implement multiple signals in a program?

I am starting to learn Python (newbie), so not much idea about the different modules etc.

Scenario that I want to simulate:

I have a program prg1.py that I want to run for some user defined time say t seconds. After this time (t seconds), the program should exit. For this I am using signal.signal() to create alarm. Below is the working code:

    import signal
    import time
    import sys

    def receive_alarm(signum, stack):
        sys.exit('Exiting!')

    signal.signal(signal.SIGALRM, receive_alarm)
    signal.alarm(10)

    while 1:
    print 'Working...'
    time.sleep(1)

The program runs for 10 seconds and then exits as expected.
Note: The while loop below is just for testing, it would be replaced by my working code.

Now I want to implement multiple signals to do different tasks at different intervals of time.

e.g. In EVERY:
5 seconds: execute a specific function fun1()
10 seconds: execute a specific function fun2(), and so on... (tasks I want to perform in the program)

I tried adding another alarm as shown below, but didn't work:

import signal
import time
import sys

def receive_alarm(signum, stack):
    sys.exit('Exiting!')

def receive_alarm_two(signup, stack):
    print 'Call to other functions!'

signal.signal(signal.SIGALRM, receive_alarm)
signal.alarm(10)

# Second Alarm
signal.signal(signal.SIGALRM, receive_alarm_two)
signal.alarm(2)

while 1:
print 'Working...'
time.sleep(1)

This doesn't work! Simple exits without any error or exit message :(

How can this functionality be implemented?

NOTE: Use of Threads is restricted.

NOTE: As I want the program to keep listening to different signals, it can't sleep i.e. cannot use time.sleep().

Upvotes: 0

Views: 3923

Answers (1)

Rory Yorke
Rory Yorke

Reputation: 2236

You should see if your requirements can be met by the sched module; also, why is multithreading not allowed?

It's possible to schedule multiple tasks with a single alarm by having the alarm occur at time intervals of the greatest common divisor of the period of your scheduled events. An example is below, but it's not very robust, e.g., if any task takes very long, the timing will be inaccurate. This is fixable (keep track of time with time.time(), and schedule the next alarm accordingly), though other problems remain (what happens if one task runs so long that the next task starts late?). My perception is that schedulers are a problem with many tricky corner cases, and that if possible you should use an existing solution, rather than writing your own.

import signal
import time

class Scheduler(object):
    """Trivial scheduler object.

    Rather use sched.scheduler"""

    def __init__(self):
        self._tasks= [(1,self._heartbeat)]
        self._tick= 0
        self.stopped=False

    def addtask(self,period,task):
        """Add a task to be executed every PERIOD seconds

        addtask(period,task)

        period: seconds
        task: callable taking 'tick' argument
        """
        self._tasks.append( (period,task) )

    def _heartbeat(self,tick):
        print 'heartbeat: %d' % tick

    def _execute(self,signum,stack):
        if self.stopped:
            return

        self._tick += 1
        for period, task in self._tasks:
            if 0==self._tick % period:
                task(self._tick)
        signal.alarm(1)

    def start(self):
        signal.signal(signal.SIGALRM, self._execute)
        signal.alarm(1)

    def stop(self):
        self.stopped=True

class Stopper(object):
    """Callable to stop a scheduler"""
    def __init__(self, scheduler):
        self._scheduler=scheduler

    def __call__(self,tick):
        print 'stopping at tick',tick
        self._scheduler.stop()

def task3s(tick):
    print '3s task at tick',tick

def task7s(tick):
    print '7s task at tick',tick

s= Scheduler()
s.addtask(10,Stopper(s))
s.start()

s.addtask(3,task3s)
s.addtask(7,task7s)

while not s.stopped:
    time.sleep(0.5)
    print 'mainloop...'

On my (python2) system this gives:

mainloop...
heartbeat: 1
mainloop...
mainloop...
heartbeat: 2
mainloop...
mainloop...
heartbeat: 3
3s task at tick 3
mainloop...
mainloop...
heartbeat: 4
mainloop...
mainloop...
heartbeat: 5
mainloop...
mainloop...
heartbeat: 6
3s task at tick 6
mainloop...
mainloop...
heartbeat: 7
7s task at tick 7
mainloop...
mainloop...
heartbeat: 8
mainloop...
mainloop...
heartbeat: 9
3s task at tick 9
mainloop...
mainloop...
heartbeat: 10
stopping at tick 10
mainloop...

Upvotes: 4

Related Questions