从后台线程在主UI线程中调用lambda / std :: function

时间:2016-04-01 09:32:24

标签: c++ multithreading qt

我是我的主线程,我有一个Qt窗口正在运行,它正在调用我的后台线程(网络服务),并最终期待应该在UI中反映的响应:

// runs in main (GUI) thread
void QTServer::onButtonClick(){
    srv->request(msg, 
        [this]
           (std::shared_ptr<message> msg){
              this->ui.txtResponse->setText("received a response" + msg.data());
            });
}

网络服务如下:

std::function<void(std::shared_ptr<message>)> delegate_;

void NetworkService::request(message& msg,std::function<void(std::shared_ptr<message> msg)> fn)
{
    // send the request to the socket and store the callback for later
    // ...
    this->delegate_ = fn;
}

void NetworkService::onResponseReceived(std::shared_ptr<message> responseMsg)
{
    // is called from the background thread (service)
    // Here I would like to call the lambda function that the service stored somewhere (currently as an std::func member)

    // psuedo: call In Main Thread: delegate_(responseMsg);
}

这是如何工作的?它甚至可以工作吗?

我知道您可以使用QMetaObject::invokeMethod(this, "method", Qt::QueuedConnection来调用mainthread中的函数,所以我尝试了以下内容:

void NetworkService::onResponseReceived(std::shared_ptr<message> responseMsg)
{
    QMetaObject::invokeMethod(this, "runInMainThread", Qt::QueuedConnection, QGenericArgument(), Q_ARG(std::function<void(std::shared_ptr<message>)>, delegate_));
}

如何在此处传递responseMsg作为_delegate的参数?

 void QTServer::runInMainThread(std::function<void(std::shared_ptr<message>)> f) {
    f(); 
}

如何摆脱“没有这些参数的函数”错误?

2 个答案:

答案 0 :(得分:1)

删除QGenericArgument() - 它是内部帮助器类。 您还必须注册自己的类型才能使用Q_ARG或将数据作为void *发送回来。

Q_ARG(void*, delegate_)

第二个问题 - f是一个函数,它接受一个参数--std :: shared_ptr,和f() - 不带参数调用,所以添加默认参数

答案 1 :(得分:-1)

我认为在QT中尝试实现的推荐方法是将信号和插槽与QThread结合使用。例如:

MyObject * myObject = new MyObject(); //your worker
QThread * myThread = new QThread(); //your thread
myObject->moveToThread(myThread);

QObject::connect(myThread, SIGNAL(started()), myObject, SLOT(startWorking())); //when thread starts, invoke the working method
QObject::connect(myObject, SIGNAL(stoppedWorking()), this, SLOT(stoppedWorking())); //when worker signals it finished, invoke slot in main

QObject::connect(myObject, SIGNAL(stoppedWorking()), myThread, SLOT(quit())); //quit the thread when worker signals that it finished
QObject::connect(myObject, SIGNAL(gproxyExiting()), gproxy, SLOT(deleteLater())); //cleanup
QObject::connect(myThread, SIGNAL(finished()), myThread, SLOT(deleteLater())); //cleanup

这样就可以自动管理整个生命周期,您可以定义工作线程内的任何信号和主线程上的插槽,以便相互通信。