使用QT线程解决运行时问题

时间:2014-12-02 11:38:54

标签: c++ multithreading qt race-condition

我目前的问题是两个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,而且为了简化操作,我只添加了一个外部函数。但在我不想让我的步进器混淆之后,我想限制访问,如上所述。

2 个答案:

答案 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

  

阻塞排队连接就像一个排队连接,但发送方线程阻塞,直到接收器所在线程的事件循环拾取事件,调用插槽,然后返回;