views:

226

answers:

8

Hi!

I'm working with the Gnuradio framework. I handle flowgraphs I generate to send/receive signals. These flowgraphs initialize and start, but they don't return the control flow to my application:

I imported time

while time.time() < endtime:
        # invoke GRC flowgraph for 1st sequence
        if not seq1_sent:
            tb = send_seq_2.top_block()
            tb.Run(True)
            seq1_sent = True
            if time.time() < endtime:
                break

        # invoke GRC flowgraph for 2nd sequence
        if not seq2_sent:
            tb = send_seq_2.top_block()
            tb.Run(True)
            seq2_sent = True
            if time.time() < endtime:
                break

The problem is: only the first if statement invokes the flow-graph (that interacts with the hardware). I'm stuck in this. I could use a Thread, but I'm unexperienced how to timeout threads in Python. I doubt that this is possible, because it seems killing threads isn't within the APIs. This script only has to work on Linux...

How do you handle blocking functions with Python properly - without killing the whole program. Another more concrete example for this problem is:

import signal, os

def handler(signum, frame):
        # print 'Signal handler called with signal', signum
        #raise IOError("Couldn't open device!")
        import time
        print "wait"
        time.sleep(3)


def foo():
    # Set the signal handler and a 5-second alarm
    signal.signal(signal.SIGALRM, handler)
    signal.alarm(3)

    # This open() may hang indefinitely
    fd = os.open('/dev/ttys0', os.O_RDWR)
    signal.alarm(0)          # Disable the alarm


foo()
print "hallo"

How do I still get print "hallo". ;)

Thanks, Marius

A: 

If you want to set a timeout on a blocking function, threading.Thread as the method join(timeout) which blocks until the timeout.

Basically, something like that should do what you want :

import threading
my_thread = threading.Thread(target=send_seq_2.top_block)
my_thread.start()
my_thread.join(TIMEOUT)
mripard
Every CPU intensive task in threads should be avoided though, because of the GIL.
mripard
That doesn't meet his requirements. If the timeout has passed, join fails - but he actually would want to abort the thread, which isn't possible.
Martin v. Löwis
+2  A: 

You can set a signal alarm that will interrupt your call with a timeout:

http://docs.python.org/library/signal.html

signal.alarm(1) # 1 second

my_blocking_call()
signal.alarm(0)

You can also set a signal handler if you want to make sure it won't destroy your application:

def my_handler(signum, frame):
    pass

signal.signal(signal.SIGALRM, my_handler)

EDIT: What's wrong with this piece of code ? This should not abort your application:

import signal, time

def handler(signum, frame):
    print "Timed-out"

def foo():
    # Set the signal handler and a 5-second alarm
    signal.signal(signal.SIGALRM, handler)
    signal.alarm(3)

    # This open() may hang indefinitely
    time.sleep(5)
    signal.alarm(0)          # Disable the alarm


foo()
print "hallo"

The thing is:

  1. The default handler for SIGALRM is to abort the application, if you set your handler then it should no longer stop the application.

  2. Receiving a signal usually interrupts system calls (then unblocks your application)

Antoine Pelisse
hmh, it seems when I do that I lose the whole program instead of just ending the blocked calls.
wishi
+4  A: 

IIUC, each top_block has a stop method. So you actually can run the top_block in a thread, and issue a stop if the timeout has arrived. It would be better if the top_block's wait() also had a timeout, but alas, it doesn't.

In the main thread, you then need to wait for two cases: a) the top_block completes, and b) the timeout expires. Busy-waits are evil :-), so you should use the thread's join-with-timeout to wait for the thread. If the thread is still alive after the join, you need to stop the top_run.

Martin v. Löwis