Quantcast

GnuRadio flowgraphs in workerthread

classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

GnuRadio flowgraphs in workerthread

Alex3371
Hello guys,

would it affect the performance of my GNURadio-programm negatively if I tried to run my GNURadio flowgraphs in a workerthread instead of the mainthread. In the mainthread I would like to implement a custom wxPython GUI.

Also, I still do not understand what the happens when I call wait() and/or stop(). I have two flowgraphs, one for receiving and one for transmitting with the USRP2. Both use a gr.head block and run to completion after they have proccessed a certain ammount of samples. I did some testing and it seems to work fine. But still I would like to know if the following lines of Code make any sense:

main():

receiver = receiver_class()

transmitter = transmitter_class()

while(1):

______receiver.run()
______transmitter.run()
______# reset the head blocks and some other stuff:
______update_attributes()

Can I use run() OR should I use start() + wait() OR start(), wait() + stop() ?

Regards
Alex Peterson

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: GnuRadio flowgraphs in workerthread

Johnathan Corgan-3
On 10/11/2013 07:52 AM, Alex3371 wrote:

> would it affect the performance of my GNURadio-programm negatively if
> I tried to run my GNURadio flowgraphs in a workerthread instead of
> the mainthread. In the mainthread I would like to implement a custom
> wxPython GUI.

It is entirely possible to instantiate a GNU Radio flowgraph in a
separate thread from the main one, though it's not clear in your use
case if it is needed. There is no performance impact. The runtime will
create individual threads for each block anyway.

> Also, I still do not understand what the happens when I call wait()
> and/or stop(). I have two flowgraphs, one for receiving and one for
> transmitting with the USRP2. Both use a gr.head block and run to
> completion after they have proccessed a certain ammount of samples.

The run() function on a top block is a wrapper around calls to start()
and wait().  The flowgraph will operate either until it exits on it's
own or until it is terminated by a signal (like ctrl-c).  The calling
thread context is blocked waiting for the internal wait() call to
return.  This is the typical way to run flowgraphs that don't need to do
anything else in the calling thread context.

You can retain control of the calling thread context by instead doing
this manually.

Calling start() on a top block creates a running thread per block (among
many other things), then returns to the calling context. You are free
then to do anything else needed in your application, and the GNU Radio
flowgraph runs "in the background."  This is how you would run control
code in Python that talks to the flowgraph through some mechanism like
messaging or function calls on individual blocks.

To end the flowgraph at some point, you call stop(), which sends an
interrupt to each of the GNU Radio block threads.  Finally, you call
wait(), which internally joins all the interrupted threads, so that when
wait() returns, all the flowgraph threads are known to have completed.

> I did some testing and it seems to work fine. But still I would like
>  to know if the following lines of Code make any sense:

In your case, since you are using head blocks, the flowgraph will exit
on its own when the requested number of samples have passed through the
head block.  However, you are trying to coordinate the activity of two
separate top blocks.  If you called run() on the first one, it would not
return from that call until the flowgraph exited, and your second
flowgraph would get started too late.

The first way to solve this is to call start() on each top block, then
call wait() each of them sequentially.  Thus, the two flowgraphs operate
simultaneously, and each one "exits" when its head block is done.  The
calls to wait() will ensure that your application while loop does not
continue until this happens.

The second (and better) way to do this is to put both signal processing
chains into one flowgraph.  Convert each of them to a hierarchical block
with no inputs or outputs, then create a top block, and use the
tb.connect() method:

tb = gr.top_block()
receiver = receiver_class() # now a hierarchical block with no I/O
transmitter = transmitter_class() # also a hierarchical block

tb.connect(receiver)
tb.connect(transmitter)

while (1):
        tb.start() # starts threads
        # Do stuff while the flowgraph is running (if needed)
        tb.wait() # blocks until both hier blocks are in done state
        # Do stuff in between flowgraph runs (if needed)

In your particular case, since you are using head blocks in both chains,
you could use run() in the loop instead of start() and wait(). The
flowgraph would finish naturally and run() would return.  This would not
let you, however, do anything while the flowgraph was running.

Finally, if you ever change the flowgraph such that it "runs forever"
instead of exiting on its own, you'd need to have a call to tb.stop() in
there at the point your control logic needs to shut things down.

Hope this makes things clearer.

--
Johnathan Corgan, Corgan Labs
SDR Training and Development Services
http://corganlabs.com

_______________________________________________
Discuss-gnuradio mailing list
[hidden email]
https://lists.gnu.org/mailman/listinfo/discuss-gnuradio

johnathan.vcf (460 bytes) Download Attachment
signature.asc (237 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: GnuRadio flowgraphs in workerthread

Alex3371
Wow, thank you for your detailed answer.

But one thing I don't understand:

" If you called run() on the first one, it would not
return from that call until the flowgraph exited, and your second
flowgraph would get started too late. "

I don't want the flowgraphs to run parallel to each other. One flowgraph senses the spectrum with the USRP and the second flowgraph transmitts a signal with the same USRP (depending on the measurements of the spectrum). So it's important that they run consecutively.

In this case, is it fine the way I do call run() for both flowgraphs? Would replacing it with start() + wait() make any difference?

Also, I hope you don't mind if I add one more questions:

When the flowgraph is stopped by a head-block the threads are shutdown, but the flowgraph itself still exists with all the blockinternal member variables (including possible changes during the first run) and after a head-reset it can be re-run with the run()-method. This re-run starts where the previous run stopped. Is that correct?









Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: GnuRadio flowgraphs in workerthread

Johnathan Corgan-3
On 10/11/2013 11:48 AM, Alex3371 wrote:

> Wow, thank you for your detailed answer.
>
> But one thing I don't understand:
>
> " If you called run() on the first one, it would not return from that
> call until the flowgraph exited, and your second flowgraph would get
> started too late. "
>
> I don't want the flowgraphs to run parallel to each other. One
> flowgraph senses the spectrum with the USRP and the second flowgraph
> transmitts a signal with the same USRP (depending on the measurements
> of the spectrum). So it's important that they run consecutively.
Ah, I missed this.

> In this case, is it fine the way I do call run() for both flowgraphs?
> Would replacing it with start() + wait() make any difference?

Since you have a finite length flowgraph, there really is no difference.

> When the flowgraph is stopped by a head-block the threads are
> shutdown, but the flowgraph itself still exists with all the
> blockinternal member variables (including possible changes during the
> first run) and after a head-reset it can be re-run with the
> run()-method. This re-run starts where the previous run stopped. Is
> that correct?

Yes.  On occasion we've found bugs in blocks that assumed their start()
functions would only get called once (like in the ALSA audio
source/sinks) but otherwise this is how it works.

I would suggest, however, that you reconsider this approach if you are
eventually going to be doing anything more than simple processing.
Starting and stopping flowgraphs is using a very heavy hammer and takes
a long time (in sample terms).

Instead, think of always having the two flowgraphs instatiated and
started, and adding a message input port to a custom block on the
transmitter and message output port to a custom block on the receiver.

You can then move your control logic into a Python message only block
that receives a message from the receiver, does whatever needs to be
done as a result of this, then triggers the transmitter by sending a
message to it.

The flowgraph then is always running, but you've separated your signal
processing control from flowgraph run/start/stop/wait semantics.

You can also extend this idea of a control block to allow triggering the
receiver (via message passing) from a GUI button, which can have an
event handler in the Python block to trigger the receiver via message.

(This description is missing details on how this would change your
flowgraphs to be message triggered, as I'm not aware of what's in them.)

Asynchronous messaging is a very new feature of GNU Radio and we don't
have many examples of using it to learn from.  But the above scenario is
one use case we had in mind in designing it.

--
Johnathan Corgan, Corgan Labs
SDR Training and Development Services
http://corganlabs.com

_______________________________________________
Discuss-gnuradio mailing list
[hidden email]
https://lists.gnu.org/mailman/listinfo/discuss-gnuradio

johnathan.vcf (460 bytes) Download Attachment
signature.asc (237 bytes) Download Attachment
Loading...