在QThread的上下文中调用方法

时间:2009-08-01 13:27:33

标签: c++ multithreading qt qthread

在我的应用程序中有主线程和工作线程(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在QThread doWork中打印。

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

5 个答案:

答案 0 :(得分:3)

问题是接收者(QThread)'生活'在主线程中,因此主线程的事件循环是执行槽的那个。

来自Qt的文档:

  

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

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

答案 1 :(得分:2)

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

答案 2 :(得分:2)

此示例显示了如何拆分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();
    }
};

答案 3 :(得分:1)

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

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

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

答案 4 :(得分:0)

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