Qt线程两个参数

时间:2017-03-16 08:03:41

标签: c++ multithreading qt

我希望使用QThread构建我的Qt应用程序,因为我想将长进程表单MainWindow与线程分开。

我在此代码中遇到了问题:

class Worker : public QObject
{
    Q_OBJECT

public slots:
    void doWork(const std::string &param2, std::string &param2) {
        int result;
        /* ... here is the expensive or blocking operation ... */
        emit resultReady(result);
    }

signals:
    void resultReady(const int &result);
};

class Controller : public QObject
{
    Q_OBJECT
    QThread workerThread;
public:
    Controller() {
        Worker *worker = new Worker;
        worker->moveToThread(&workerThread);
        connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater);
        connect(this, &Controller::input,&Controller::output, worker, &Worker::doWork);
        connect(worker, &Worker::resultReady, this, &Controller::handleResults);
        workerThread.start();
    }
    ~Controller() {
        workerThread.quit();
        workerThread.wait();
    }
public slots:
    void handleResults(const int &);
private:
    string input;
    string output;
};

我希望我的代码可以将两个值(输入,输出)字符串传输到QThread,并且结果将信号作为int值发出。但是,列出的代码不起作用。我在.Net中寻找类似blackgroundWorker的解决方案并具有类似的功能。

我应该这样做吗?

修改

我无法编译这个。我收到了错误:

Severity    Code    Description Project File    Line    Suppression State
Error   C2664   'QMetaObject::Connection QObject::connect(const QObject *,const char *,const char *,Qt::ConnectionType) const': cannot convert argument 2 from 'std::string Controller::* ' to 'const char *'   GPCTool C:\repo\Tool\Controller.cpp 21  

2 个答案:

答案 0 :(得分:0)

首先,这行代码不起作用:

connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater);

workerThread存在于主线程中,而worker存在于由workerThread处理的线程中。因此,当QThread::finished被触发时,QObject::deleteLater将被异步调用(参见Qt::AutoConnection),但是线程已经完成,异步调用永远不会完成。

甚至变得更糟。即使调用QObject::deleteLater,也不会发生延迟删除,原因相同:线程已经完成。

connect(this, &Controller::input, &Controller::output, worker, &Worker::doWork);

此调用与connect()的任何原型都不匹配。您无法将变量连接到插槽。

创建一个中间信号:

class Controller : public QObject
{
    Q_OBJECT
    QThread workerThread;
public:
    Controller() {
        Worker *worker = new Worker;
        worker->moveToThread(&workerThread);
        connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater);
        connect(this, &Controller::callDoWork, worker, &Worker::doWork);
        connect(worker, &Worker::resultReady, this, &Controller::handleResults);
        workerThread.start();
        emit callDoWork(input, output);
    }
    ~Controller() {
        workerThread.quit();
        workerThread.wait();
    }
signals:
    emit callDoWork(std::string, str::string);
public slots:
    void handleResults(const int &);
private:
    string input;
    string output;
};

或使用QMetaObject::invokeMethod()

Controller() {
    Worker *worker = new Worker;
    worker->moveToThread(&workerThread);
    connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater);

    connect(worker, &Worker::resultReady, this, &Controller::handleResults);
    workerThread.start();
    QMetaObject::invokeMethod(worker, "doWork", Qt::QueuedConnection, Q_ARG(std::string, input), Q_ARG(std::string, output));
}

请注意,要使这2个解决方案正常工作,您需要使用Q_DECLARE_METATYPE和qRegisterMetaType注册std::string(请参阅http://doc.qt.io/qt-5/qmetatype.html#Q_DECLARE_METATYPE)。

并且您还希望将std:string &output替换为std::string *output,因为Qt会在两个主题之间复制output,您将看不到更改反映到原始output变量。

connect(worker, &Worker::resultReady, this, &Controller::handleResults);

由于resultReady的签名与handleResults不匹配,因此无法编译。要将信号连接到插槽,它们必须采用相同的参数。

我建议你阅读Qt Signal & Slots documentation

关于你对线程的使用,我认为你应该看看QThreadPoolQRunnable

答案 1 :(得分:0)

你可能会读到一个愚蠢的博客,声称必须创建一个工作者对象并将其与普通线程一起使用,而不是简单地从QThread派生并实现run()

由于您的工作量只需要一次只需要一次,所以更容易做到这一点。

在任何一种情况下,只需通过构造函数或setter方法将值传递给类,实际上不需要将它们作为参数传递给doWork()