代码之家  ›  专栏  ›  技术社区  ›  Idan K

在QThread的上下文中调用方法

  •  5
  • Idan K  · 技术社区  · 15 年前

    在我的应用程序中,有一个主线程和一个工作线程( QThread
    我想从主线程调用我的工作线程的一个方法,并让它在线程的上下文中运行。

    我试过使用 QMetaObject::invokeMethod 给它一个 QueuedConnection 选项,但它不起作用。

    下面是我大致尝试的一个片段:

    class Worker : public QThread
    {
        Q_OBJECT
    
    public:
        Worker() { }
    
        void run() 
        { 
            qDebug() << "new thread id " << QThread::currentThreadId(); 
            exec(); 
        }
    
    public slots:
        void doWork()
        {
            qDebug() << "executing thread id - " << QThread::currentThreadId();
        }
    };
    

    使用QMetaObject方法:

    int main(int argc, char *argv[])
    {
        QCoreApplication a(argc, argv);
    
        qDebug() << "main thread id - " << QThread::currentThreadId();
    
        Worker worker;
        worker.start();
    
        QMetaObject::invokeMethod(&worker, "doWork", Qt::QueuedConnection);
    
        return a.exec();
    }
    

    使用信号方式:

    class Dummy : public QObject
    {
        Q_OBJECT
    
    public:
        Dummy() { }
    
    public slots:
        void askWork() { emit work(); }
    
    signals:
        void work();
    };
    
    int main(int argc, char *argv[])
    {
        QCoreApplication a(argc, argv);
    
        qDebug() << "main thread id - " << QThread::currentThreadId();
    
        Worker worker;
        worker.start();
    
        Dummy dummy;
        QObject::connect(&dummy, SIGNAL(work()), &worker, SLOT(doWork()), Qt::QueuedConnection);
    
        QTimer::singleShot(1000, &dummy, SLOT(askWork()));
    
        return a.exec();
    }
    

    这两种方式都会导致主线程id打印在 doWork

    此外,我还考虑过实现一个简单的生产者-消费者模型,但如果这能奏效,有什么理由不这样做吗?

    5 回复  |  直到 7 年前
        1
  •  3
  •   Idan K    15 年前

    问题在于接收器(QThread)“存在”于主线程中,因此主线程的事件循环是执行插槽的循环。

    从Qt的文档:

    因此,到目前为止,我找到的解决方案是在线程的run()内创建一个对象,并使用其插槽。这样,接收方的所有者就是线程,然后在线程上下文中调用插槽。

        2
  •  2
  •   Ropez    15 年前

    本例显示了如何拆分工人类,使其按您的需要工作。您还需要提供一个指向Worker实例的引用或指针,以便能够连接到插槽。

    class Worker : public QObject
    {
        Q_OBJECT
    
    public:
        Worker() { }
    
    public slots:
        void doWork()
        {
            qDebug() << "executing thread id - " << QThread::currentThreadId();
        }
    };
    
    class WorkerThread : public QThread
    {
        Q_OBJECT
    
    public:
        void run()
        {
            qDebug() << "new thread id " << QThread::currentThreadId(); 
            Worker worker;
            exec();
        }
    };
    
        3
  •  2
  •   x29a Martin Beckett    10 年前

    对于简单的生产者消费者示例,请查看Bradley T.Hughes的博客条目 Treading without the headache .

        4
  •  1
  •   Sam    12 年前

    工作线程是在主线程中创建的,因此它的事件是在主线程中处理的。您必须将辅助线程移动到它自己的线程:

    Worker worker;
    worker.moveToThread(&worker);
    worker.start();
    

    worker 位于新线程中,并将在该事件循环中对事件进行排队。

        5
  •  -1
  •   steve    15 年前

    看起来您的工作线程在调用任何函数或向其发送信号之前就完成了。