【问题标题】:Invoking methods in QThread's context在 QThread 的上下文中调用方法
【发布时间】:2010-11-16 00:56:47
【问题描述】:

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

我尝试使用 QMetaObject::invokeMethod 并为其指定 QueuedConnection 选项,但它不起作用。
我也尝试过从主线程(连接到工作线程的插槽)发出信号,但也失败了。

这是我尝试过的大致的sn-p:

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

这两种方式都会导致在QThread doWork 中打印主线程ID。

另外,我想过实现一个简单的生产者-消费者,但如果可行,有什么理由不这样做吗?

【问题讨论】:

    标签: c++ multithreading qt qthread


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

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

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

      现在 Qt 知道 worker 存在于新线程中,并将在该事件循环中对事件进行排队。

      【讨论】:

        【解决方案3】:

        这个例子展示了如何拆分 Worker 类,让它按照你的意愿工作。您还需要提供指向 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();
            }
        };
        

        【讨论】:

          【解决方案4】:

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

          来自 Qt 的文档:

          对于排队连接,当控制返回到对象所属线程的事件循环时,将调用插槽。该槽在接收者对象所在的线程中执行。

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

          【讨论】:

            【解决方案5】:

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

            【讨论】:

            • 由于调用了 exec(),工作线程在它的事件循环中
            猜你喜欢
            • 2011-01-21
            • 1970-01-01
            • 2023-01-16
            • 1970-01-01
            • 1970-01-01
            • 2013-08-15
            • 1970-01-01
            • 1970-01-01
            • 2014-08-12
            相关资源
            最近更新 更多