PySide,pySerial和threading导致段错误

时间:2014-04-10 15:25:35

标签: multithreading qt segmentation-fault pyside pyserial

我试图使用PySide和pySerial来创建一个与串口交互的跨平台应用程序。我最初使用Qtimers来轮询串行数据,但是这给cpu带来了很大的负担。所以我一直在尝试使用线程。

不幸的是,使用线程会导致Qt或pySerial陷入Segfault。

我已经尝试了python线程和QThreads,同样的问题,它发生在OSX,Windows 8和Ubuntu 12.04上。使用python 2.7和Qt4

This question seemed to have a similar problem, here:

this thread also seems to be a similar 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()

有时需要一些数据IO来触发段错误,有时单个字符会触发它......

我不确定如何进一步调试这个......

所有帮助表示赞赏!!!!!!

更新

我用不同的方法重新创建了问题,并在Qt community forum上提出了同样的问题

1 个答案:

答案 0 :(得分:2)

Qt对象不是线程安全的,所以调用

ui.plain_edit.appendPlainText(text)
来自另一个线程的

很糟糕。

解决这个问题的方法是使用QThreads和内置的线程安全消息和事件系统 类似的东西:

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  

以及以下内容将其连接起来:

serial_thread = receivePort()
serial_thread.message.connect(write_terminal, QtCore.Qt.QueuedConnection)
serial_thread.start()

其中write_terminal的签名为:

def write_terminal(text):
    ui.plain_edit.appendPlainText(text)