如何在不同的线程中运行同一类的两个函数

时间:2018-11-21 14:09:08

标签: qt class qthread

嗨,我有一个名为search的类,该类有两个成员函数。消费者和生产者。这就是我在qt中将这些功能激活为两个线程的方式。

for usr in User.objects.all():
    backend_list = []
    if usr.has_usable_password():
        backend_list.append('ModelBackend')
    if ... :                                  # what should I check here ?
        backend_list.append('OtherBackend')

    print(usr, backend_list)

但是,似乎只有一个被激活。我应该如何同时激活两者。请让我知道一个例子。

谢谢。

1 个答案:

答案 0 :(得分:0)

这是一个简单的示例,可以在两个不同的线程中运行同一对象的两个方法。假设您的Search类如下所示:

class Search : public QObject
{
    Q_OBJECT

public:
    void producer();
    void consumer();

signals:
    void workRequested();
    void finishedscan();
};

您将像这样创建第二个类:

class Worker : public QObject
{
    Q_OBJECT

public:
    Worker(std::function<void()> task) :
        QObject{},
        _task{std::move(task)}
    {}

public slots:
    void work() {
        _task();
    }

private:
    std::function<void()> _task;
};

现在您可以实施开始了:

thread1 = new QThread();
thread2 = new QThread();
mySearch = new Search();
auto worker1 = new Worker(std::bind(&Search::producer, mySearch));
auto worker2 = new Worker(std::bind(&Search::consumer, mySearch));

worker1->moveToThread(thread1);
worker2->moveToThread(thread2);

connect(mySearch, SIGNAL(workRequested()), thread1, SLOT(start()));
connect(mySearch, SIGNAL(workRequested()), thread2, SLOT(start()));

connect(thread1, SIGNAL(started()),worker1, SLOT(work()));
connect(thread2, SIGNAL(started()),worker2, SLOT(work()));

connect(mySearch, SIGNAL(finishedscan()), thread1, SLOT(quit()), Qt::DirectConnection);
connect(mySearch, SIGNAL(finishedscan()), thread2, SLOT(quit()), Qt::DirectConnection);

重要提示::此解决方案解决了如何在不同线程上启动的两个任务,但是停止停止仍然无法进行,因为QThread::quit仅在该线程有效时有效返回到事件循环!如果您的生产者/消费者方法没有返回事件循环并使用它来执行任务,请在注释中写上这样,我也将更新答案以处理这种情况。


编辑:由于仅在上述解决方案中起作用,因此如果生产者/消费者返回到事件循环(根据OP并非如此),则必须手动通知工作人员该事件应停止努力优雅地退出线程。

对于第一个解决方案,您的工人必须定期检查是否应该停止工作。例如:

MySearch::producer() {
    while(!QThread::currentThread()->isInterruptionRequested() {
        //do some work 
    }
}

其次,您必须调整退出线程的方式:

connect(mySearch, &MySearch::finishedscan, thread1, [thread1](){
    thread1->requestInterruption();
    thread1->quit();
}, Qt::DirectConnection);

注意:无论您如何退出线程,都应始终在主线程中等待它们完成其工作,然后退出:

thread1->wait();

最后,您在注释中提到使用CTRL+C退出应用程序-确保注册信号处理程序以捕获SIGINT并优雅地停止您的应用程序,将其作为默认{{1} }会终止它,而没有适当的清理