我正在使用QSerialPort与硬件设备进行通信。新数据不会发出“readyRead” - 信号,所以我决定使用QThread写一个读线程。
这是代码:
void ReadThread::run()
{
while(true){
readData();
if (buffer.size() > 0) parseData();
}
}
和
void ReadThread::readData()
{
buffer.append(device->readAll();
}
缓冲区是私有QByteArray,设备是指向QSerialPort的指针。 ParseData将解析数据并发出一些信号。当parseData被保留时,缓冲区被清除。
这是有效的,但是经过一段时间(有时是10秒,有时是1小时),程序会与SIGSEGV崩溃,并带有以下描述:
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7ffff3498700 (LWP 24870)]
malloc_consolidate (av=av@entry=0x7fffec000020) at malloc.c:4151
(gdb) bt
#0 malloc_consolidate (av=av@entry=0x7fffec000020) at malloc.c:4151
#1 0x00007ffff62c2ee8 in _int_malloc (av=av@entry=0x7fffec000020, bytes=bytes@entry=32769) at malloc.c:3423
#2 0x00007ffff62c4661 in _int_realloc (av=av@entry=0x7fffec000020, oldp=oldp@entry=0x7fffec0013b0, oldsize=oldsize@entry=64, nb=nb@entry=32784) at malloc.c:4286
#3 0x00007ffff62c57b9 in __GI___libc_realloc (oldmem=0x7fffec0013c0, bytes=32768) at malloc.c:3029
#4 0x00007ffff70d1cdd in QByteArray::reallocData(unsigned int, QFlags<QArrayData::AllocationOption>) () from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5
#5 0x00007ffff70d1f07 in QByteArray::resize(int) () from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5
#6 0x00007ffff799f9fc in free (bytes=<optimized out>, this=0x609458)
at ../../include/QtSerialPort/5.3.2/QtSerialPort/private/../../../../../src/serialport/qt4support/include/private/qringbuffer_p.h:140
#7 read (maxLength=<optimized out>, data=<optimized out>, this=0x609458)
at ../../include/QtSerialPort/5.3.2/QtSerialPort/private/../../../../../src/serialport/qt4support/include/private/qringbuffer_p.h:326
#8 QSerialPort::readData (this=<optimized out>, data=<optimized out>, maxSize=<optimized out>) at qserialport.cpp:1341
#9 0x00007ffff722bdf0 in QIODevice::read(char*, long long) () from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5
#10 0x00007ffff722cbaf in QIODevice::readAll() () from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5
#11 0x00007ffff7bd0741 in readThread::readData (this=0x6066c0) at ../reader.cpp:212
#12 0x00007ffff7bc80d0 in readThread::run (this=0x6066c0) at ../reader.cpp:16
#13 0x00007ffff70cdd2e in ?? () from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5
#14 0x00007ffff6e1c0a4 in start_thread (arg=0x7ffff3498700) at pthread_create.c:309
#15 0x00007ffff632f04d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:111
我不确定如何正确地重现问题,因为它是随机出现的。如果我在while循环中注释掉“readData()”,则不会再出现崩溃(当然也无法解析数据)。
有没有人知道这可能是什么?
答案 0 :(得分:0)
什么是缓冲区?可能是,另一个线程是从缓冲区读取数据并在之后清除它?
尝试锁定它(以及线程之间共享的所有其他数据),例如使用互斥锁
QMutex mx; // could be also member of the ReadThread class
void ReadThread::readData()
{
mx.lock();
buffer.append(device->readAll();
mx.unlock();
}
在从另一个线程读取和清除缓冲区的代码中执行相同的操作(我不做假设,这是parseData())
另一种可能性是,parseData()调用一些在GUI-Thread中运行的代码。这在Qt4中可能不起作用,也可能在Qt5中起作用
答案 1 :(得分:0)
您一次使用多个线程中的QObject
实例。一般来说,这会导致未定义的行为,正如您刚刚看到的那样。 QSerialPort
可以在GUI线程上正常工作。只有一旦你在那里工作,你可以将它移动到工作线程。
请注意,如果事件循环(app.exec()
或main()
中的QThread::run()
来电)未执行,则信号将不会发生。看起来好像你试图编写伪同步代码并且(可预测地)失败了。别这么做。
这样的事情应该有效:
#include <QtCore>
#include <QtSerialPort>
int main(int argc, char ** argv) {
QCoreApplication app(argc, argv);
QSerialPort port;
port.setPortName(...);
port.setBaudRate(...);
... // etc
if (! port.open(QIODevice::ReadWrite)) {
qWarning() << "can't open the port";
return 1;
}
... // set the port
connect(&port, &QIODevice::readyRead, [&]{
qDebug() << "got" << port.readAll().size() << "bytes";
});
return app.exec(); // the signals will be emitted from here
}
答案 2 :(得分:0)
确保初始化所有与串行端口相关的对象,并仅在单独的线程中使用。使用signal / slot-mechanism将接收到的数据或已解析的事件发送到UI线程。
另请注意,如果在readThread中继承QThread,则构造函数可以在UI线程和readThread中的其他函数中执行。在这种情况下,启动readThread并在其他函数之前运行单独的初始化函数(例如,通过从UI线程发送适当的信号)。