Pregunta

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!!!!!!

UPDATE

I've recreated the the problem with different hard, and have asked this same question on the Qt community forum

¿Fue útil?

Solución

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)
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top