在主线程中向其他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_())