我目前的问题是两个QT线程。其中一个发出信号以在第二个线程中启动操作,然后等待结果。第二个线程完成后,第一个线程应该使用第二个线程的结果继续自己的操作。
为了让第一个线程休眠我使用QMutex和QWaitCondition。第一个线程发出信号,然后在等待条件下休眠。但问题是现在:如果第二个线程设法比第一个线程更快,并且在第一个线程进入等待条件之前发出wakeAll() - 调用,我就会卡住。我可以实现一个等待时间,但后来我再也不灵活了,如果第二个线程需要的时间比第一个线程等待的时间多,我又遇到了问题。
此问题已在此处解决:http://woboq.com/blog/qwaitcondition-solving-unavoidable-race.html,但他们决定将此问题解决。那么,是否有可能避免这种竞争条件?
另外:我不想将此函数转换为第一个线程的函数,因为此特定函数应该可以同时从多个线程访问而不会导致竞争条件。即Thread1应该调用Thread2中的函数,等到它完成,Thread3也想调用该函数,但是不允许这样做,它也要等到完成。如果函数已完成,则Thread3可以访问它。 (同样只有两个线程)。
示例功能:
此功能应发出信号,然后等待唤醒信号:
void Spectrometer_Control::moveStepper(int steps, bool dir)
{
emit stepperMoving();
qDebug() << "From Spectrometer_Control: Stepper should move in direction " + QString::number(dir) + " from position " + QString::number(MonoPos);
int newTarget = MonoPos + ((dir == true)?(steps):(-1 * steps));
qDebug() << "New target: " + QString::number(newTarget);
emit moveStepperToTarget(steps, dir);
qDebug() << "Locking WaitMutex!";
WaitMutex->lock();
qDebug() << "Waiting for signal!";
WaitForEngine->wait(WaitMutex);
WaitMutex->unlock();
qDebug() << "Finally unlocked!";
}
此函数接收呼叫,并应唤醒每个等待功能:
void Stepper_Control_Worker::moveStepper(int steps, bool dir)
{
waitMutex->lock();
qDebug() << "Motor moved from down below!";
Stepper_Control_Worker::STP[1]->setValue((dir == true)?BlackLib::high:BlackLib::low);
usleep(50000);
Stepper_Control_Worker::STP[0]->setValue(BlackLib::low);
usleep(50000);
for(int i = 0; i < steps; i++)
{
Stepper_Control_Worker::STP[0]->setValue(BlackLib::high);
usleep(50000);
Stepper_Control_Worker::STP[0]->setValue(BlackLib::low);
}
WaitCond->wakeAll();
waitMutex->unlock();
emit StepperMoved(steps, dir);
}
第二个函数是“stepper_control”类的子成员(不是直接,但只能通过访问)。步进控制器外部控件可以由多个函数使用,不仅是Spectrometer_Control的函数moveStepper,而且为了简化操作,我只添加了一个外部函数。但在我不想让我的步进器混淆之后,我想限制访问,如上所述。
答案 0 :(得分:2)
让第二个线程发回信号并将代码发送等待到那个插槽可能是安全的。
class Worker1: public QObject{
Q_OBJECT
//...
signals:
void startWorking();
slots:
void answer(QVariant);
};
class Worker2: public QObject{
Q_OBJECT
//...
slots:
void startWorking();
signals:
void answer(QVariant);
};
否则你需要有一个第二个线程设置的变量,同时按住QMutex
来表示第一个:
线程1:
emit startWorking();
{
QMutexLocker lock(&thread2->mutex);
while(!thread2->finished){//loop guards against spurious wakeups
thread2->cond->wait(&mutex);
}
}
和thread2:
{
QMutexLocker lock(&mutex);
finished=true;
cond->wakeAll();
}
这样,如果thread2更快,那么{1}}在thread1到达时已经为真,并且互斥锁在测试它并等待thread2->finished
之间保护变量。
答案 1 :(得分:0)
也许你需要Qt::BlockingQueuedConnection
?
阻塞排队连接就像一个排队连接,但发送方线程阻塞,直到接收器所在线程的事件循环拾取事件,调用插槽,然后返回;