如何在单独的线程上设置QSerialPort?

ana*_*ius 6 c++ qt qthread qtserialport qtcore

按照官方文档,我正在尝试这样做:

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent)
{
    QThread *thread = new QThread;    
    Worker *worker= new Worker();

    worker->moveToThread(thread);

    //init connections

    thread->start();
}
Run Code Online (Sandbox Code Playgroud)

工人构造函数:

Worker::Worker(QObject *parent) :
    QObject(parent)
{
    serial = new QSerialPort(this);  //passing the parent, which should be the current thread      
}
Run Code Online (Sandbox Code Playgroud)

没有编译错误但是当我执行它时会抛出这个:

QObject: Cannot create children for a parent that is in a different thread. 
(Parent is QSerialPort(0x11bd1148), parent's thread is QThread(0x11bd2ef8), current thread is QThread(0x3e47b8)
Run Code Online (Sandbox Code Playgroud)

也就是说,它告诉我serial作为父线程的主线程而不是我创建的线程.

如果我不在构造函数中实例化序列但在主进程中实例化相同的结果,这是在我们调用之后触发的thread->start():

Worker::Worker(QObject *parent) :
    QObject(parent)
{             
}

Worker::doWork()
{
    if(!serial)
        serial= new QSerialPort(this); 

    //...
}
Run Code Online (Sandbox Code Playgroud)

我错过了什么?


发送功能作为示例(插槽):

void Worker::send(const QByteArray &data)
{
    serial->write(data);
    if( serial->waitForBytesWritten(TIMEOUT) )
        qDebug() << "sent: " << data;
}
Run Code Online (Sandbox Code Playgroud)

lpa*_*app 7

简而言之,像这样使用QtSerialPort模块是个坏主意.

我们基于QIODevice设计了这个模块,它已经为您的GUI应用程序提供了使用QSerialPort类的非阻塞机制.

您应该查看以下信号:

void QIODevice :: bytesWritten(qint64 bytes)[signal]

每次将数据有效载荷写入设备时都会发出此信号.bytes参数设置为在此有效负载中写入的字节数.bytesWritten()不是递归发出的; 如果重新进入事件循环或在连接到bytesWritten()信号的槽内调用waitForBytesWritten(),则不会重新发送信号(尽管waitForBytesWritten()可能仍然返回true).

和...

void QIODevice :: readyRead()[signal]

每当有新数据可供设备读取时,该信号就会发出一次.只有在新数据可用时才会再次发出它,例如网络数据的新有效负载已经到达网络套接字,或者新的数据块已经附加到您的设备上.

readyRead()不是递归发出的; 如果你重新进入事件循环或在连接到readyRead()信号的槽内调用waitForReadyRead(),则不会重新发送信号(尽管waitForReadyRead()仍然可以返回true).

对于实现从QIODevice派生的类的开发人员的注意事项:当新数据到达时,您应该总是发出readyRead()(不要仅仅因为仍然要在缓冲区中读取数据而发出它).不要在其他条件下发出readyRead().

我通过命令行写了两个例子,你可以在这里找到:

命令行编写器异步示例

命令行读取器同步示例

  • 我需要从串口读取数据并给它一个时间戳,这需要有点准确.由于[QT的消息循环冻结,例如当您在标题栏上按住鼠标左键时](http://www.qtcentre.org/threads/51858),因此无法使用QT的消息循环获得准确的时间戳,因此线程是必需的.有没有办法用QtSerialPort获得可靠的时间戳,除了创建一个单独的进程,然后将数据和时间戳传递给主进程? (3认同)
  • 找到关于阻止open()调用的评论的解决方案.为了防止来自冻结GUI的open()调用,应该创建(!)QSerialPort并在非gui线程中打开.这意味着不应该在Worker类的构造函数中创建QSerialPort.并且不要将'this'(of worker)传递给QSerialPort的构造函数. (2认同)