# How do I know when my flow graph has finished in a non-blocking way?

**URL:** <https://www.ruby-forum.com/t/how-do-i-know-when-my-flow-graph-has-finished-in-a-non-blocking-way/230757>\
**Category:** GNU Radio\
**Created:** [July 2, 2014, 8:29pm UTC](https://www.ruby-forum.com/t/how-do-i-know-when-my-flow-graph-has-finished-in-a-non-blocking-way/230757 "2014-07-02T20:29:00Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![addis\_a](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/c4cdca/32.png) [@addis\_a](https://www.ruby-forum.com/u/addis_a)\
**Post date:** [July 2, 2014, 8:29pm UTC](https://www.ruby-forum.com/t/how-do-i-know-when-my-flow-graph-has-finished-in-a-non-blocking-way/230757/1 "2014-07-02T20:29:00Z")

</div>

Dear friends of GNU Radio,  
I have a question about blocking, threads and GUI. Thing is, I am  
writing  
an GUI application (in PyQT4) where the user can start a GNU Radio  
flowgraph by a button. The flowgraph records data from an USRP and some  
additional blocks. Now, I want only a finite amount of data so I have  
added  
a “head” block to my flowgraph. The obvious way to run this is as the  
following pseudo code program:

# Define flowgraph

class USRP(gr.top\_block)  
…connect USRP -\> head\_block\_\> file\_sink

# Define GUI

GUI\_\_init\_\_()  
gui.button.clicked.connect(startUSRP) …

# Define action to be taken when button clicked, i.e. start flowgraph

startUSRP()  
tb=USRP()  
tb.start()  
tb.wait() # Will block everything until finished

# define and run GUI

main()  
app = QtGui.QApplication(sys.argv)  
window = main\_window()  
window.show()  
sys.exit(app.exec\_())  
if **name** == ‘ **main** ’:  
main()

My code runs as expected, in the sense data is produced, but tb.wait is  
a  
blocking call. This means that my GUI will freeze until the flowgraph  
has  
ended. The GUI must not be blocked during flowgraph execution. Also, I  
would like to track the progress of the flowgraph (the number of  
elements  
processed / total elements requested). I tried to search online, and  
there  
is some related information, but unfortunately I have not managed to  
understand how to put the pieces together yet. I imagine something like  
using QTimer to periodically check the status of the flowgraph, by  
asking  
the flowgraph in some way.  
This flowgraph ends with writing to a file, after the head\_block. Hence,  
I  
suspect that just checking the head\_block might not give me all data?  
Either I need to add a small extra delay to make sure the file sink gets  
all data, or check the number of items passed to the file sink itself?  
So I  
guess the short question is:  
How to periodically check if a started flowgraph has finished, without  
using a blocking call such as tb.wait?

I would be very grateful for any hints. I don’t know much about C++ and  
threading, which makes finding clues from the C++ API more difficult.  
However, I am eager to learn if anyone would enlighten me on this.

Best regards,  
Eskil

---

<div class="post-metadata">

**Author:** ![Eskil\_Varenius](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/3ec8ea/32.png) [@Eskil\_Varenius](https://www.ruby-forum.com/u/Eskil_Varenius)\
**Post date:** [July 2, 2014, 9:09pm UTC](https://www.ruby-forum.com/t/how-do-i-know-when-my-flow-graph-has-finished-in-a-non-blocking-way/230757/2 "2014-07-02T21:09:30Z")

</div>

Hi Eskil,

QT has its own threading library that you’ll need to use to spawn a new  
thread to do the blocking calls in:  
[QThread Class Reference](http://pyqt.sourceforge.net/Docs/PyQt4/qthread.html) (sadly, that page is  
still C++ centric)

PyQT4 usually comes with a set of nice examples, which have been useful  
for me over the last days; for me, those installed to  
/usr/share/doc/PyQt4-devel-4.10.1/examples  
and for your threading intents, you might want to look at  
/usr/share/doc/PyQt4-devel-4.10.1/examples/network/threadedfortuneserver.py

Greetings, and happy hacking,  
Marcus

---

<div class="post-metadata">

**Author:** ![Eskil\_Varenius](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/3ec8ea/32.png) [@Eskil\_Varenius](https://www.ruby-forum.com/u/Eskil_Varenius)\
**Post date:** [July 3, 2014, 11:59am UTC](https://www.ruby-forum.com/t/how-do-i-know-when-my-flow-graph-has-finished-in-a-non-blocking-way/230757/3 "2014-07-03T11:59:47Z")

</div>

Dear Marcus,  
Thank you very much for that advice. After thinking and reading a bit  
more  
based on what you wrote, I think I managed to solve my problem! I attach  
a  
brief example I wrote to try it out, including only the essential things  
+  
simple plotting.

Regarding the examples you mentioned: In my system (Linux Mint 17), to  
be  
able to check the examples you mentioned, I had to install the docs by  
“sudo aptget python-qt4-doc” and they were then accessible at  
“/usr/share/doc/python-qt4-doc/examples/network/threadedfortuneserver.py”.  
I learned some good things here, but regarding threading I found this  
page  
even more useful (which I found once I realised what I was looking for,  
thanks to you):  
[http://stackoverflow.com/questions/6783194/background-thread-with-qthread-in-pyqt](http://stackoverflow.com/questions/6783194/background-thread-with-qthread-in-pyqt)

I also went ahead and implemented a simple graphics window as well, with  
help of this page:  
[http://stackoverflow.com/questions/12459811/how-to-embed-matplotib-in-pyqt-for-dummies](http://stackoverflow.com/questions/12459811/how-to-embed-matplotib-in-pyqt-for-dummies)

I am relatively new to Qt and threading, so I am sure I make mistakes  
and  
have bad coding style. But, since this simple test program works, I  
thought  
I might as well share it anyway. Since I myself find much information as  
text online, I include in this email also below the code I wrote as text  
(not as attached files), with hopes that it might be useful for someone  
searching for related things online.

Best regards,  
Eskil

* * *

SUMMARY of the test program:  
Shows a window on screen where the user can click a button to start a  
GNUradio flowgraph. The flowgraph will run in a separate thread to not  
disturb the UI. When data has been generated by GNUradio, the user can  
plot  
the data on screen. Tested on Linux Mint 17 computer using gnuradio  
3.7.2  
(as available via apt-get) and relevant Python2/PyQt4 modules.

List of files included:  
Main.py – The main program to be run by the user.  
FlowGraph.grc – Flowgraph made with GNUradio-companion. Used to  
generate  
(in GRC) the file top\_block.py.  
top\_block.py – File generated automatically by GRC. This contains all  
GNURadio code for the flowgraph. Used in Main.py. When the flowgraph is  
run, it will generate a file called “threadingdata.dat” with samples  
from a  
signal generator.  
GUI.ui – Graphical user interface created with QtDesigner. Used to  
generate GUI.py.  
GUI.py – Generated from GUI.ui by running “pyuic4 GUI.ui \> GUI.py” in  
terminal. Used in Main.py.

PASTED CODE FOR EACH FILE BELOW:  
-------Main.py-------  
#!/usr/bin/env python  
from matplotlib.backends.backend\_qt4agg import FigureCanvasQTAgg as  
FigureCanvas  
from matplotlib.backends.backend\_qt4agg import NavigationToolbar2QTAgg  
as  
NavigationToolbar  
import matplotlib.pyplot as plt  
from GUI import Ui\_Dialog  
from PyQt4 import QtGui, QtCore  
import sys  
from top\_block import \*  
import numpy as np

# Define object used to run GNUradio in a separate QThread, according

to:

# 

[http://stackoverflow.com/questions/6783194/background-thread-with-qthread-in-pyqt](http://stackoverflow.com/questions/6783194/background-thread-with-qthread-in-pyqt)  
class Worker(QtCore.QObject):  
finished = QtCore.pyqtSignal()

```
@QtCore.pyqtSlot()
def runflowgraph(self):
    self.tb.start()
    self.tb.wait()
    self.finished.emit()

```

# Implement custom Thread class, according to:

# 

[http://stackoverflow.com/questions/6783194/background-thread-with-qthread-in-pyqt](http://stackoverflow.com/questions/6783194/background-thread-with-qthread-in-pyqt)  
class Thread(QtCore.QThread):  
def **init** (self, parent=None):  
QtCore.QThread. **init** (self, parent)

```
def start(self):
    QtCore.QThread.start(self)

def run(self):
    QtCore.QThread.run(self)

```

# Define GUI, using the code generated by QtDesigner.

# Made by running in terminal “pyuic4 GUI.ui \> GUI.py” to get GUI.py

containing class Ui\_Dialog.  
class main\_Dialog(Ui\_Dialog, QtGui.QDialog):  
def **init** (self):  
super(main\_Dialog, self). **init** ()  
self.setupUi(self)  
self.init\_Ui()

```
# Set states of interface and connect button signals
# to relevant slots.
def init_Ui(self):
    self.testGUIbutton.clicked.connect(self.showGUIisalive)
    self.getdatabutton.clicked.connect(self.runGNURadio)
    self.plotresbutton.clicked.connect(self.plot)

    # Do not allow plotting before data has been taken
    self.plotresbutton.setEnabled(False)

    # ADD MATPLOTLIB CANVAS, based on:
    #

```

[http://stackoverflow.com/questions/12459811/how-to-embed-matplotib-in-pyqt-for-dummies](http://stackoverflow.com/questions/12459811/how-to-embed-matplotib-in-pyqt-for-dummies)  
# a figure instance to plot on  
self.figure = plt.figure()  
# this is the Canvas Widget that displays the `figure`  
# it takes the `figure` instance as a parameter to **init**  
self.canvas = FigureCanvas(self.figure)  
self.canvas.setParent(self)  
# set the layout  
# Position as left, top, width, height  
self.canvas.setGeometry(QtCore.QRect(400, 160, 271, 300))

```
# Show that GUI is responsive when this slot is activated by GUI.
def showGUIisalive(self):
    self.logmsg('GUI alive!')

# Create worker object and QThread to handle GNURadio execution in 

```

the  
background  
# without blocking the UI. This will run a simple flowgraph with a  
# signal generator, generating a file with floating  
# point numbers that can later be plotted.  
# Based on  
[http://stackoverflow.com/questions/6783194/background-thread-with-qthread-in-pyqt](http://stackoverflow.com/questions/6783194/background-thread-with-qthread-in-pyqt)  
def runGNURadio(self):  
self.plotresbutton.setEnabled(False)  
self.getdatabutton.setEnabled(False)  
self.obj = Worker()  
self.obj.tb = top\_block()  
self.thread = Thread() # Create thread to run GNURadio in  
background  
self.obj.moveToThread(self.thread)  
self.obj.finished.connect(self.thread.quit)  
self.thread.finished.connect(self.GNUradiofinished)  
self.thread.started.connect(self.obj.runflowgraph)  
self.logmsg(‘GNURadio started.’)  
self.thread.start() # Will run the GNU radio flow graph

```
# Things to do when GNURadio is finished, such as enable plotting.
def GNUradiofinished(self):
    self.logmsg('GNURadio finished.')
    self.getdatabutton.setEnabled(True)
    self.plotresbutton.setEnabled(True)

# Put message in textwindow
def logmsg(self, msg):

```

self.plainTextEdit.appendPlainText(QtCore.QDateTime.currentDateTime().toString()

- ': ’ + msg )

# Run main event loop and show GUI on screen.

def main():  
app = QtGui.QApplication(sys.argv)  
dialog = main\_Dialog()  
dialog.show()  
sys.exit(app.exec\_())

# If this file is run (e.g. from terminal by “python Main.py”, then run

code, else act as library.  
if **name** == ‘ **main** ’:  
main()

-------FlowGraph.grc-------

\<?xml version='1.0' encoding='ASCII'?\>

\<flow\_graph\>  
Thu Jul 3 09:48:33 2014  
  
options  
  
id  
top\_block  
  
  
\_enabled  
True  
  
  
title  
  
  
  
author  
  
  
  
description  
  
  
  
window\_size  
1280, 1024  
  
  
generate\_options  
no\_gui  
  
  
category  
Custom  
  
  
run\_options  
run  
  
  
run  
True  
  
  
max\_nouts  
0  
  
  
realtime\_scheduling  
  
  
  
\_coordinate  
(10, 10)  
  
  
\_rotation  
0  
  
  
  
variable  
  
id  
time\_seconds  
  
  
\_enabled  
True  
  
  
value  
5  
  
  
\_coordinate  
(299, 19)  
  
  
\_rotation  
0  
  
  
  
variable  
  
id  
samp\_rate  
  
  
\_enabled  
True  
  
  
value  
32000  
  
  
\_coordinate  
(200, 16)  
  
  
\_rotation  
0  
  
  
  
analog\_sig\_source\_x  
  
id  
analog\_sig\_source\_x\_0  
  
  
\_enabled  
True  
  
  
type  
float  
  
  
samp\_rate  
samp\_rate  
  
  
waveform  
analog.GR\_COS\_WAVE  
  
  
freq  
1000  
  
  
amp  
1  
  
  
offset  
0  
  
  
affinity  
  
  
  
minoutbuf  
0  
  
  
maxoutbuf  
0  
  
  
\_coordinate  
(16, 112)  
  
  
\_rotation  
0  
  
  
  
blocks\_throttle  
  
id  
blocks\_throttle\_0  
  
  
\_enabled  
True  
  
  
type  
float  
  
  
samples\_per\_second  
samp\_rate  
  
  
vlen  
1  
  
  
affinity  
  
  
  
minoutbuf  
0  
  
  
maxoutbuf  
0  
  
  
\_coordinate  
(211, 104)  
  
  
\_rotation  
0  
  
  
  
blocks\_head  
  
id  
blocks\_head\_0  
  
  
\_enabled  
True  
  
  
type  
float  
  
  
num\_items  
time\_seconds\*samp\_rate  
  
  
vlen  
1  
  
  
affinity  
  
  
  
minoutbuf  
0  
  
  
maxoutbuf  
0  
  
  
\_coordinate  
(240, 190)  
  
  
\_rotation  
0  
  
  
  
blocks\_file\_sink  
  
id  
blocks\_file\_sink\_0  
  
  
\_enabled  
True  
  
  
file  
threadingdata.dat  
  
  
type  
float  
  
  
vlen  
1  
  
  
unbuffered  
False  
  
  
append  
False  
  
  
affinity  
  
  
  
\_coordinate  
(202, 261)  
  
  
\_rotation  
0  
  
  
  
\<source\_block\_id\>blocks\_head\_0\</source\_block\_id\>  
\<sink\_block\_id\>blocks\_file\_sink\_0\</sink\_block\_id\>  
\<source\_key\>0\</source\_key\>  
\<sink\_key\>0\</sink\_key\>  
  
  
\<source\_block\_id\>analog\_sig\_source\_x\_0\</source\_block\_id\>  
\<sink\_block\_id\>blocks\_throttle\_0\</sink\_block\_id\>  
\<source\_key\>0\</source\_key\>  
\<sink\_key\>0\</sink\_key\>  
  
  
\<source\_block\_id\>blocks\_throttle\_0\</source\_block\_id\>  
\<sink\_block\_id\>blocks\_head\_0\</sink\_block\_id\>  
\<source\_key\>0\</source\_key\>  
\<sink\_key\>0\</sink\_key\>  
  
\</flow\_graph\>  
-------top\_block.py-------  
#!/usr/bin/env python  
##################################################

# Gnuradio Python Flow Graph

# Title: Top Block

# Generated: Thu Jul 3 09:48:35 2014

##################################################

from gnuradio import analog  
from gnuradio import blocks  
from gnuradio import eng\_notation  
from gnuradio import gr  
from gnuradio.eng\_option import eng\_option  
from gnuradio.filter import firdes  
from optparse import OptionParser

class top\_block(gr.top\_block):

```
def __init__ (self):
    gr.top_block. __init__ (self, "Top Block")

    ##################################################
    # Variables
    ##################################################
    self.time_seconds = time_seconds = 5
    self.samp_rate = samp_rate = 32000

    ##################################################
    # Blocks
    ##################################################
    self.blocks_throttle_0 = blocks.throttle(gr.sizeof_float*1,

```

samp\_rate)  
self.blocks\_head\_0 = blocks.head(gr.sizeof\_float_1,  
time\_seconds_samp\_rate)  
self.blocks\_file\_sink\_0 = blocks.file\_sink(gr.sizeof\_float\*1,  
“threadingdata.dat”, False)  
self.blocks\_file\_sink\_0.set\_unbuffered(False)  
self.analog\_sig\_source\_x\_0 = analog.sig\_source\_f(samp\_rate,  
analog.GR\_COS\_WAVE, 1000, 1, 0)

```
    ##################################################
    # Connections
    ##################################################
    self.connect((self.blocks_head_0, 0), (self.blocks_file_sink_0, 

```

0))  
self.connect((self.analog\_sig\_source\_x\_0, 0),  
(self.blocks\_throttle\_0, 0))  
self.connect((self.blocks\_throttle\_0, 0), (self.blocks\_head\_0,  
0))

# QT sink close method reimplementation

```
def get_time_seconds(self):
    return self.time_seconds

def set_time_seconds(self, time_seconds):
    self.time_seconds = time_seconds

def get_samp_rate(self):
    return self.samp_rate

def set_samp_rate(self, samp_rate):
    self.samp_rate = samp_rate
    self.analog_sig_source_x_0.set_sampling_freq(self.samp_rate)
    self.blocks_throttle_0.set_sample_rate(self.samp_rate)

```

if **name** == ‘ **main** ’:  
parser = OptionParser(option\_class=eng\_option, usage=“%prog:  
[options#]”)  
(options, args) = parser.parse\_args()  
tb = top\_block()  
tb.start()  
tb.wait()  
-------GUI.ui-------

\<?xml version="1.0" encoding="UTF-8"?\> Dialog 0 0 724 503 Dialog 50 50 201 41 Run GNU Radio in background 40 140 131 31 Test GUI (print) 380 50 131 31 Plotdata 40 230 71 16 Textoutput 390 110 58 15 Graph 40 260 311 171 -------GUI.py------- # -\*- coding: utf-8 -\*-
# Form implementation generated from reading ui file ‘GUI.ui’

# 

# Created: Thu Jul 3 11:17:09 2014

# by: PyQt4 UI code generator 4.10.4

# 

# WARNING! All changes made in this file will be lost!

from PyQt4 import QtCore, QtGui

try:  
\_fromUtf8 = QtCore.QString.fromUtf8  
except AttributeError:  
def \_fromUtf8(s):  
return s

try:  
\_encoding = QtGui.QApplication.UnicodeUTF8  
def \_translate(context, text, disambig):  
return QtGui.QApplication.translate(context, text, disambig,  
\_encoding)  
except AttributeError:  
def \_translate(context, text, disambig):  
return QtGui.QApplication.translate(context, text, disambig)

class Ui\_Dialog(object):  
def setupUi(self, Dialog):  
Dialog.setObjectName(\_fromUtf8(“Dialog”))  
Dialog.resize(724, 503)  
self.getdatabutton = QtGui.QPushButton(Dialog)  
self.getdatabutton.setGeometry(QtCore.QRect(50, 50, 201, 41))  
self.getdatabutton.setObjectName(\_fromUtf8(“getdatabutton”))  
self.testGUIbutton = QtGui.QPushButton(Dialog)  
self.testGUIbutton.setGeometry(QtCore.QRect(40, 140, 131, 31))  
self.testGUIbutton.setObjectName(\_fromUtf8(“testGUIbutton”))  
self.plotresbutton = QtGui.QPushButton(Dialog)  
self.plotresbutton.setGeometry(QtCore.QRect(380, 50, 131, 31))  
self.plotresbutton.setObjectName(\_fromUtf8(“plotresbutton”))  
self.textlabel = QtGui.QLabel(Dialog)  
self.textlabel.setGeometry(QtCore.QRect(40, 230, 71, 16))  
self.textlabel.setObjectName(\_fromUtf8(“textlabel”))  
self.graphlabel = QtGui.QLabel(Dialog)  
self.graphlabel.setGeometry(QtCore.QRect(390, 110, 58, 15))  
self.graphlabel.setObjectName(\_fromUtf8(“graphlabel”))  
self.plainTextEdit = QtGui.QPlainTextEdit(Dialog)  
self.plainTextEdit.setGeometry(QtCore.QRect(40, 260, 311, 171))  
self.plainTextEdit.setObjectName(\_fromUtf8(“plainTextEdit”))

```
    self.retranslateUi(Dialog)
    QtCore.QMetaObject.connectSlotsByName(Dialog)

def retranslateUi(self, Dialog):
    Dialog.setWindowTitle(_translate("Dialog", "Dialog", None))
    self.getdatabutton.setText(_translate("Dialog", "Run GNU Radio 

```

in  
background", None))  
self.testGUIbutton.setText(\_translate(“Dialog”, “Test GUI  
(print)”,  
None))  
self.plotresbutton.setText(\_translate(“Dialog”, “Plotdata”,  
None))  
self.textlabel.setText(\_translate(“Dialog”, “Textoutput”, None))  
self.graphlabel.setText(\_translate(“Dialog”, “Graph”, None))

2014-07-02 21:07 GMT+02:00 Marcus Müller [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid):
