首页 > 开发 > C++ > 正文

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

2017-09-11 21:34:59  来源: 网友分享

在主线程中向其他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_OBJECTpublic:    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 4class DataSender : public QObject{    Q_OBJECTpublic:    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);}

解决方案

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

#/usr/bin/env python# -*- coding: utf-8 -*-import sysimport timefrom PyQt4 import QtCore, QtGuiclass 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_())