6

在我的应用程序中有一个主线程和一个工作线程(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.

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

4

5 回答 5

3

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

来自 Qt 的文档:

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

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

于 2009-08-01T19:05:21.657 回答
2

对于简单的生产者-消费者示例,请查看 Bradley T. Hughes Treading 的博客条目,而不会感到头疼

于 2009-08-02T08:08:06.363 回答
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();
    }
};
于 2009-08-11T18:27:16.767 回答
1

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

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

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

于 2012-06-20T01:59:40.360 回答
-1

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

于 2009-08-01T18:38:41.787 回答