怎样在qt中触发多线程并行运算?


在主线程中向其他n个子线程发送event,让子线程并行运算,运算完成后向主线程发送信号,并等待下一次event到达。而主线程则等待所有子线程运算完成后,再次发送event。

我用postEvent向子线程发送消息,然后调用sendPostedEvent,发现子线程是按照postEvent的先后顺序执行的,并不是并行的运算。

比如有4个calculator线程,其中id 0的运算0秒,id 1的运算1秒,... id 3的运算3秒,就是id越小的运算越早结束, 如果同时计算完成的顺序应该是0,1,2,3。如果按照0 ~ 3的顺序向calculator发送事件,是这个顺序。而按照3 ~ 0的顺序发送,完成的顺序是3,2,1,0. 而不是我想象中的0,1,2,3.

请问,在这种情况下,应该怎样触发多线程的并行运算?谢谢!

代码:
calculator.h


 #ifndef CALCULATOR_H
#define CALCULATOR_H

#include <QObject>
#include <QThread>
#include <QEvent>

class Calculator : public QThread
{
    Q_OBJECT
public:
    explicit Calculator(int thread_id, int sleep_interval, QObject *parent = 0)
        : QThread(parent)
        , thread_id_(thread_id)
        , sleep_interval_(sleep_interval)
    {}

    void stop(int /*exit_code*/) {
        QThread::exit();
        sleep(sleep_interval_);
        emit resultReady(thread_id_);
    }

protected:
    void run() Q_DECL_OVERRIDE{
        exec(); //wait for event
    }

    bool event(QEvent */*myevent*/) {
        sleep(sleep_interval_);
        emit cal_finished(thread_id_);  //return thread id
        return true;
    }

signals:
    void cal_finished(int result);
    void resultReady(int result);

private:
    int thread_id_;
    int sleep_interval_;
};


#endif // CALCULATOR_H

DataSender.h


 #ifndef DATASENDER_H
#define DATASENDER_H

#include <QCoreApplication>
#include "calculator.h"
#include <iostream>
#define THREAD_NUMBER 4

class DataSender : public QObject
{
    Q_OBJECT
public:
    explicit DataSender(QObject *parent = 0) : QObject(parent) {}

public slots:
    void run() {
        //generate and run 4 calculators thread
        Calculator* calculator[THREAD_NUMBER];
        for (int i = 0; i < THREAD_NUMBER; ++i) {
            calculator[i] = new Calculator(i, i, this);
            connect(calculator[i], &Calculator::resultReady , this, &DataSender::handleResults);
            connect(calculator[i], &Calculator::cal_finished, this, &DataSender::cal_finished);
        }

        //post event to thread 0 ~ 3
        for (int j = 0; j < THREAD_NUMBER; ++j)
            QCoreApplication::postEvent(calculator[j], new QEvent(QEvent::User));
        QCoreApplication::sendPostedEvents();
        sleep(4); //wait 4 seconds

        //post event to thread 3 ~ 0
        for (int j = THREAD_NUMBER - 1; j >= 0; --j)
            QCoreApplication::postEvent(calculator[j], new QEvent(QEvent::User));
        QCoreApplication::sendPostedEvents();
        sleep(4); //wait 4 seconds*/


        for (int i = 0; i < THREAD_NUMBER; ++i)
            delete calculator[i];

        emit signalFinished();
    }

    void cal_finished(int result) {
        std::cout << "Thread #" << result << " done.\n";
    }

    void handleResults(int thread_id) {
        std::cout << "Thread #" << thread_id << "Exit\n";
    }

signals:
    void signalFinished();
};

#endif // DATASENDER_H

main.cpp


 #include <QCoreApplication>
#include <QTimer>

#include "calculator.h"
#include "datasender.h"


int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);
    DataSender* dataSender = new DataSender(&app);

    QObject::connect(dataSender, SIGNAL(signalFinished()), &app, SLOT(quit()));
    QTimer::singleShot(0, dataSender, SLOT(run()));

    app.exec();

    delete dataSender;
    return (0);
}

QT C++

伊卡洛斯不落 10 years, 9 months ago

参考: http://blog.iceyer.net/archives/how-to-use-qtcore-qthread/
QThread不是通过继承来使用的,而是一种系统资源。需要配合moveToThread使用,给一段简单的python代码做示范:


 #/usr/bin/env python
# -*- coding: utf-8 -*-

import sys
import time
from PyQt4 import QtCore, QtGui

class Worker(QtCore.QObject):
    def __init__(self, parent = None):
        QtCore.QObject.__init__(self, parent)

    def runx(self):
        while True:
            print("Worker is working...")
            time.sleep(5)

class MainView(QtGui.QWidget):
    def __init__(self, parent = None):
        QtGui.QWidget.__init__(self, parent)

        self.worker = Worker()
        ###delete 3 line below will make mainview block
        **self.workerThread = QtCore.QThread()
        self.worker.moveToThread(self.workerThread)
        self.workerThread.start()**        
        ###
        self.runsignal = QtCore.SIGNAL("runx(PyQt_PyObject)") 
        self.connect(self.worker, self.runsignal, self.worker.runx)
        self.worker.emit(self.runsignal, self.worker)


if "__main__" == __name__:
    app = QtGui.QApplication(sys.argv)

    mv = MainView()
    mv.show()

    sys.exit(app.exec_())

霧雨·潶白 answered 10 years, 9 months ago

Your Answer