我有两个类,一个Handler和一个与信号和插槽连接的Worker。这是一个简化版本(伪代码):
Handler构造函数:
Handler::Handler(QObject *parent) : QObject(parent)
{
m_workerThread = new QThread;
m_worker = new Worker;
m_worker->moveToThread(m_workerThread);
m_workerThread->start();
connect(this, &Handler::doWork, m_worker, &Worker::doWork);
connect(this, &Handler::stopWork, m_worker, &Worker::stopWork);
emit doWork();
}
工人
void Worker::doWork()
{
qDebug()<<"------"
qDebug()<<"Start do work executing in: "<<QThread::currentThreadId();
//doing some work
m_timer->start();//a singleshot timer that calls doWork() on timeout
qDebug()<<"work done";
qDebug()<<"------"
}
void Worker::stopWork()
{
qDebug()<<"Stop timer executing in: "<<QThread::currentThreadId();
m_timer->stop();
}
所以基本上工作是在发出&#34; doWork&#34;之后开始的。来自Handler。 &#34; doWork&#34; slot有一个单声道定时器,在一段时间后再次调用相同的功能。 一段时间后,Handler发出了#stop; stopWork&#34;信号。 这是我的调试输出:
------
Start do work executing in: 0x65602450
work done
------
------
Start do work executing in: 0x65602450
work done
------
------
Start do work executing in: 0x65602450
work done
------
------
Start do work executing in: 0x65602450
stop work emitted from handler in: 0x750a7000
Stop timer executing in: 0x65602450
work done
------
------
Start do work executing in: 0x65602450
work done
------
etc...
所以我不明白我的工作线程是如何同时执行两个插槽(doWork和stopWork)的?在执行&#34; stopWork&#34;之前,不应该发布stopWork信号并等待线程变为空闲状态。槽?
不幸的是,我无法使用最小的工作示例来重现这一点,但我希望从我发布的代码中明白我错过了什么。
同样从我的测试中我发现这种情况发生在30-40%的时间。
答案 0 :(得分:0)
使用QMutex和/或QSemaphore等线程同步类可能会解决您的问题。
例如,如果您在Handler类中创建了一个QMutex并将其传递给您的工作线程:
Handler::Handler(QObject *parent) : QObject(parent)
{
//Class variable : QMutex* mutex
mutex = new QMutex();
m_workerThread = new QThread;
m_worker = new Worker;
m_worker->moveToThread(m_workerThread);
m_workerThread->start();
connect(this, &Handler::doWork, m_worker, &Worker::doWork);
connect(this, &Handler::stopWork, m_worker, &Worker::stopWork,Qt::BlockingQueuedConnection);
emit doWork(mutex);
}
然后从另一个线程内部调用这个常见的QMutex锁定机制:
void Worker::doWork(QMutex* mutex)
{
mutex->lock();
qDebug()<<"------"
qDebug()<<"Start do work executing in: "<<QThread::currentThreadId();
//doing some work
m_timer->start();//a singleshot timer that calls doWork() on timeout
qDebug()<<"work done";
qDebug()<<"------"
mutex->unlock();
}
在发出“停止”信号之前,在Handler类中使用了相同的逻辑:
...
mutex->lock();
emit stopWork();
mutex->unlock();
...
这样你就可以避免不必要的并发。
这里的BlockingQueuedConnection标志确保在没有停止作业完成的情况下主线程不会前进,因此在作业完成之前不会解锁互斥锁。
这是我在处理并发情况和数据竞争时尝试使用的逻辑,我希望它也能帮到你。