Reputation: 71
I'm trying to use PySide and pySerial to make a cross-platform app that interacts with the serial port. I originally used Qtimers to poll the serial for data, but this put a large load on the cpu. So I've been attempting to use threads instead.
unfortunately using threads causes either Qt or pySerial to Segfault.
I've tried both python threads and QThreads, same problem, it happens on OSX, windows 8 and Ubuntu 12.04. using python 2.7 and Qt4
This question seemed to have a similar problem, here:
this thread also seems to be a similar problem
below is a small app that recreates the problem
#! /usr/bin/python
import sys
import serial
import threading
from PySide import QtCore, QtGui, QtUiTools
class serial_port_class(object):
def __init__(self, ui):
self.ui = ui
self.connected = False
def __del__(self):
self.disconnect_port()
def connect_port(self):
try:
self.serial_port = serial.Serial("/dev/tty.usbmodem1451", 9600, timeout = None)
self.connected = True
except serial.SerialException, e:
self.connected = False
if self.connected:
self.serial_thread = threading.Thread(target=self.recieve_port, args=([self.ui]))
self.serial_thread.start()
def disconnect_port(self):
self.connected = False
self.serial_thread.join()
self.serial_port.close()
def recieve_port(self, ui):
while self.connected:
try:
text = self.serial_port.read(1)
if text != '':
ui.plain_edit.appendPlainText(text)
except serial.SerialException, e:
connected = False
class KeyPressEater(QtCore.QObject):
def eventFilter(self, obj, event):
global serial_port
if event.type() == QtCore.QEvent.KeyPress:
ch = event.text().encode('utf-8')
if serial_port.connected == True:
serial_port.serial_port.write(ch)
return QtCore.QObject.eventFilter(self, obj, event)
def main():
global serial_port
app = QtGui.QApplication(sys.argv)
ui = QtGui.QWidget()
ui.plain_edit = QtGui.QPlainTextEdit(ui)
keyFilter = KeyPressEater(ui)
ui.plain_edit.installEventFilter(keyFilter)
serial_port = serial_port_class(ui)
serial_port.connect_port()
ui.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
sometimes it takes a bit of data IO to trigger the segfault, sometime a single character will trigger it...
I'm not really sure how I would go about debugging this further....
All help is appreciated!!!!!!
I've recreated the the problem with different hard, and have asked this same question on the Qt community forum
Upvotes: 1
Views: 1877
Reputation: 71
Qt objects are not thread safe, so calling
ui.plain_edit.appendPlainText(text)
from another thread was bad.
a way around this is to use QThreads and the inbuilt thread safe messageing and events system something like:
class receivePort(QThread):
message = QtCore.Signal(str)
def __init__(self):
self.connected = False
QThread.__init__(self)
def run(self):
while self.connected:
try:
text = self.serial_port.read(1)
if text != '':
self.message.emit(text)
except serial.SerialException, e:
connected = False
and the following to connect it up:
serial_thread = receivePort()
serial_thread.message.connect(write_terminal, QtCore.Qt.QueuedConnection)
serial_thread.start()
where write_terminal has a signature of:
def write_terminal(text):
ui.plain_edit.appendPlainText(text)
Upvotes: 2