2015-07-30 1 views
1

Я общаюсь с аппаратным устройством, использующим QSerialPort. Новые данные не генерируют «readyRead» -Signal, поэтому я решил написать поток чтения с использованием QThread.QSerialPort :: readAll() приводит к SIGSEGV/SIGABRT, если вызывается в цикле while

Это код:

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 ([email protected]=0x7fffec000020) at malloc.c:4151 
(gdb) bt 
#0 malloc_consolidate ([email protected]=0x7fffec000020) at malloc.c:4151 
#1 0x00007ffff62c2ee8 in _int_malloc ([email protected]=0x7fffec000020, [email protected]=32769) at malloc.c:3423 
#2 0x00007ffff62c4661 in _int_realloc ([email protected]=0x7fffec000020, [email protected]=0x7fffec0013b0, [email protected]=64, [email protected]=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 

я не уверен, как правильно воспроизвести проблему, так как оно появляется случайным образом. Если я прокомментирую «readData()» в моем цикле while, сбои больше не появляются (конечно, данные не могут быть проанализированы, тогда).

Кто-нибудь знает, что это может быть?

+0

* Новые данные не испускают «readyRead» -Signal * - Я думаю, вы должны сначала изучить это.QSerialport получен из QIODevice, поэтому он, безусловно, должен испускать readyRead, когда доступны данные. – TheDarkKnight

+1

Я бы предположил, что где-то вы пишете память за пределами выделенного блока, но не в коде, который вы предоставили. Вы пробовали какие-либо другие инструменты, такие как valgrind или электрический забор? –

+0

@ TheDarkKnight Да, я посмотрю на это, конечно. – boltzmann138

ответ

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

0

Вы используете экземпляр QObject из нескольких потоков одновременно. Это, как правило, приводит к неопределенному поведению, как вы только что видели. QSerialPort будет отлично работать в потоке графического интерфейса пользователя. Только после того, как вы его заработаете, вы можете переместить его в рабочий поток.

Обратите внимание, что если цикл события (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 
} 
0

Убедитесь, что все объекты, связанные с последовательного порта инициализирован и используется только в отдельном потоке. Отправлять полученные данные или анализируемые события в поток пользовательского интерфейса с помощью механизма сигнала/слота.

Обратите внимание, что если вы наследуете QThread в readThread, конструктор может быть выполнен в потоке пользовательского интерфейса и других функциях в readThread. В этом случае запустите readThread и запустите отдельную функцию инициализации перед другими функциями (например, отправив правильный сигнал из потока пользовательского интерфейса).