代码之家  ›  专栏  ›  技术社区  ›  Link H.

对于从通过QTcpSocket的数据流连续运行复杂算法,最好的Qt线程解决方案是什么?

  •  0
  • Link H.  · 技术社区  · 7 年前

    在我目前的工作中,我继承了一个复杂的程序,我正在寻求减少来自QTCP数据流的图像闪烁。

    该程序接收连续的数据流,对其进行处理,然后使用paintEvent在屏幕上绘制。

    处理函数基于信号/插槽连接运行,其中信号来自QTcpSocket的readyread(),插槽是数据处理函数。该流是连续的,因此该信号/时隙会根据输入数据不断触发和更新屏幕上的绘制图像。

    图像不断闪烁,我假设主事件循环中的处理可能会干扰数据流,因此我的想法是将数据处理功能放在自己的线程中。这个数据处理功能是如此彻底地集成到程序的其他功能中,以至于在这一点上对数据流进行子分类以便我可以应用QThread并不是一个解决方案,而是整个程序的完整重构,需要花费大量时间。

    所以我的想法是这样使用QtConcurrent:

    void MainWindow::getDataThread(){     //implemented as a slot 
        wpFuture = QtConcurrent::run(this, &MainWindow::getData);
    }
    

    其中getData()是连接到readyread()信号的数据处理函数:

    connect(tcpSocket2, SIGNAL(readyRead()), this, SLOT(getData()));
    

    因此,我将SLOT(getData())替换为SLOT(getDataThread()),以允许在从全局线程池获得的新线程上运行数据处理函数。由于流是连续的,我相信每次运行getData处理函数时,它都会不断地分配一个新线程。它似乎确实减少了闪烁,但在大约30到60秒后,程序随机崩溃,没有特定的调用。

    所以我的问题是:有没有更好的方法来线程化我的数据处理函数,而不必对数据流进行子类化?在这种特定情况下,我在实施QtConcurrent时的想法/理解是否有误?

    非常感谢。

    1 回复  |  直到 7 年前
        1
  •  0
  •   WindyFields    7 年前

    根据您的评论,我认为您对线程池的理解是错误的。

    线程池中有许多线程。每次你打电话 QtConcurrent::run 从全局线程池中获取一个空闲线程,并交给它一个任务( MainWindow::getData ). 如果你打电话 QT并发::运行 几倍于每次 将在(可能)不同的线程中执行。如果线程池中当前没有可用的线程,您的任务将排队,并在稍后可用时交给线程。通过这种方式,您可以同时运行多个任务,这些任务受到线程池中线程数量的限制。

    现在的问题是 主窗口::getData 根据其设计,可能不是线程安全的。 QtConcurrent::run(this, &MainWindow::getData); 多次调用可能会导致数据竞争。

    如果您希望使用单独的单个线程来处理数据,那么只需使用 QThread (无需“子类化”任何内容):

    // A thread and its context are created only once  
    QThread thread;
    QObject context;
    context.moveToThread(&thread);
    // ...
    
    QObject::connect(tcpSocket2, &QTcpSocket::readyRead, &context, [this] () { 
        this->getData(); 
    }, Qt::QueuedConnection);
    
    thread.start()
    

    现在只要 context 对象处于活动状态,并且 thread 每次都在运行 QTcpSocket::readyRead

    仍然要注意,这样你的工作线程和主线程就不会发生冲突 getData .