【问题标题】:Calling lambda/std::function in main UI thread from a background thread [duplicate]从后台线程调用主 UI 线程中的 lambda/std::function [重复]
【发布时间】:2016-04-01 09:32:23
【问题描述】:

我是我的主线程,我有一个 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在主线程中调用一个函数,所以我尝试了以下方法:

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(); 
}

如何摆脱“No function with these arguments”错误?

【问题讨论】:

    标签: c++ multithreading qt


    【解决方案1】:

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

    Q_ARG(void*, delegate_)
    

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

    【讨论】:

    • 嗯,如果我尝试Q_ART(void*, delegate_),它会显示“没有可用的构造函数”
    • 传递地址Q_ARG(void*, &delegate_),然后使用reinterpret_cast)*>
    【解决方案2】:

    我相信您在 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
    

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-06-17
      • 2011-10-24
      • 1970-01-01
      • 1970-01-01
      • 2023-04-05
      • 2019-07-22
      • 1970-01-01
      • 2017-11-29
      相关资源
      最近更新 更多