QtConcurrent::run 发出信号

3
我想在Qt中发出一个信号,该信号来自我使用QtConcurrent :: run调用的函数。
是否可能?看起来我的槽从未被调用。所有的信号、槽和函数都属于同一个类对象。我尝试在主线程和从线程中进行连接。我不在意信号和槽是否在同一个线程中,我只是想让它发生。
谢谢
4个回答

3
以下内容在Qt 4.8.7中完全正常。信号从工作线程发出,由主线程消耗。我们断言插槽在主线程中运行,而函数对象在工作线程中运行。
// https://github.com/KubaO/stackoverflown/tree/master/questions/concurrent-emit-qt4-7114421
#include <QtCore>

class Helper : public QObject {
   Q_OBJECT
public:
   int n = 0;
   Q_SLOT void increment() {
      Q_ASSERT(QThread::currentThread() == qApp->thread());
      n++;
   }
};

int main(int argc, char **argv)
{
   QCoreApplication app(argc, argv);
   Helper helper;
   Q_ASSERT(helper.n == 0);
   QtConcurrent::run([&]{
      Q_ASSERT(QThread::currentThread() != qApp->thread());
      QObject src;
      QObject::connect(&src, SIGNAL(destroyed(QObject*)), &helper, SLOT(increment()));
      QObject::connect(&src, SIGNAL(destroyed(QObject*)), &app, SLOT(quit()));
   });
   app.exec();
   Q_ASSERT(helper.n == 1);
}

#include "main.moc"

在Qt5中,您不需要使用辅助类来展示其工作原理:
#include <QtConcurrent>

int main(int argc, char **argv)
{
   QCoreApplication app(argc, argv);
   int n = 0;
   Q_ASSERT(n == 0);
   QtConcurrent::run([&]{
      Q_ASSERT(QThread::currentThread() != qApp->thread());
      QObject src;
      QObject::connect(&src, &QObject::destroyed, &app, [&]{
         Q_ASSERT(QThread::currentThread() == qApp->thread());
         n ++;
         qApp->quit();
      });
   });
   app.exec();
   Q_ASSERT(n == 1);
}

Qt 对 QFuture 的语义进行了奇怪的处理,允许在协程仍在运行时销毁它,这会导致奇怪的行为。请注意,它的 ISO 类似物的析构函数会等待。严格来说,应该创建 QFuture 对象,调用 app.exec,然后等待 QFuture 完成(如果尚未完成)。 - Swift - Friday Pie

1

您可以使用Qt::QueuedConnection来建立连接(将其传递给connect调用,以建立连接),因为信号始终会从与接收对象线程不同的线程发出。

Qt::AutoConnection也会执行相同的操作,并将信号添加到接收对象的线程事件队列中。

如果接收线程被阻塞,因此永远不会重新进入事件队列,则无法通过接收对象的插槽接收信号。


这是不正确的:默认的自动连接就可以很好地完成工作。 - Kuba hasn't forgotten Monica
1
@KubaOber:你错了。OP说所有的槽和信号都属于一个对象。因此,AutoConnection将评估为DirectConnection。这可能不是OP想要的,因为这要求槽以线程安全的方式使用对象。在这种情况下,必须手动进行同步。QueuedConnection将消除手动同步的需要,因为槽将在对象所在的线程中调用。Qt将处理实现所需的同步。 - smerlin
1
发送者对象并不重要。在发出信号时进行的发送和接收线程之间的比较是在当前线程(QThread::currentThread)和目标线程(receiver->thread())之间进行的。发送对象的线程在该决定中没有任何作用。 - Kuba hasn't forgotten Monica
1
@KubaOber:确实,你是对的。我一直认为它会考虑发送对象的线程亲和性并静态地配置连接。但它确实动态地检查线程,并且始终*做正确的事情。将连接静态配置为Queued可能仍然有益,因为这样可以消除Qt比较当前/接收器线程的需要。如果信号总是从不同的线程触发,那么这种优化显然只适用于该情况。恰好这就是OP的情况。 - smerlin

0

-1

是的,这是可能的。 只需要看一个小例子:

在这个例子中,我们想要实现多线程。longProcess函数进入线程池,在线程池中处理后,长时间处理函数的答案会回到主线程。

Test.h

Class Test: public QObject
{
    Q_OBJECT
public:
    explicit Test(QObject *parent = nullptr);

    void resultAvailable();

    static void doLongProcess(Test *test);

signals:
    void finishedProcess(const QString &massage);

public slots:
    void captureSignal(const QString &message);
};

Test.cpp

void Test::resultAvailable()
{
        QtConcurrent::run(&ContactsModelManager::doLongProcess, this);

        connect(this , &Test::finishedProcess,
                this , &Test::captureSignal);
}

//attention!! doLongProcess is static fnuction
void Test::doLongProcess(Test *test)
{
    //this process is very long
    test->longProcess();
}
 void Test::longProcess()
{
    //do your process

    //at the end emit your signal 
    emit finishedProcess("finished process in another thread");
}

void Test::captureSignal(const QString &message)
{
   Qdebug() << "message is: " << message;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接