【问题标题】:Solving run-time problems with QT threads使用 QT 线程解决运行时问题
【发布时间】:2015-01-30 15:29:08
【问题描述】:

我目前的问题是两个 QT 线程。其中一个发出信号以在第二个线程中开始操作,然后等待结果。一旦第二个线程完成,第一个线程应该使用来自第二个线程的结果继续其自己的操作。

为了让第一个线程休眠,我使用了 QMutex 和 QWaitCondition。第一个线程发出一个信号,然后在等待条件下休眠。但现在的问题是:如果第二个线程以某种方式比第一个线程更快,并且在第一个线程进入等待条件之前发出了 wakeAll() 调用,我就会卡住。我可以实现一个等待时间,但是我又不灵活了,如果第二个线程需要的时间比第一个线程等待的时间长,我又遇到了问题。

此问题已在此处解决:http://woboq.com/blog/qwaitcondition-solving-unavoidable-race.html,但他们决定不解决此问题。那么,有没有可能避免这种竞争条件?

补充:我不想把这个函数转换为第一个线程的函数,因为这个特定的函数应该可以同时从多个线程访问,而不会导致竞争条件。 IE。 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,而且为了使事情更容易,我只添加了一个外部函数。但是在我不想让我的步进器感到困惑之后,我想如上所述限制访问。

【问题讨论】:

  • 如果您只想让第一个线程休眠并等待第二个线程完成,为什么还要使用第二个线程?
  • 因为我的第二个线程在另一个类中,也应该通过其他几种方式访问​​。把它放到这个类的一个函数中,就不可能在其他线程的其他函数中使用它,这也必须等待它。 (AFAIK,错了吗)?
  • 线程不驻留在类中。 QThread 更像是一个线程控制器。从 QObject 派生的类可以移动到不同的线程。尽管如此,我仍然不明白为什么需要创建第二个线程。线程允许并发处理,(根据您的描述)您的应用程序没有使用它。如果您发布问题的示例代码,您可能会收到更好的响应,而缺少这可能是为什么有人(不是我)决定对您的问题投反对票的原因。
  • @Merlin069:这段代码是否应该完整且可运行?
  • 理想情况下是的,但如果不是,只要是一个能清楚地描述问题的最小示例,就可以了。听起来您的问题更多是与类之间的通信有关的设计问题,而不是与线程有关的任何问题。

标签: c++ multithreading qt race-condition


【解决方案1】:

也许Qt::BlockingQueuedConnection 是你需要的?

阻塞队列连接类似于队列连接,但发送者线程阻塞,直到接收者所在线程的事件循环拾取事件,调用槽,然后返回;

【讨论】:

    【解决方案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);
        }
    }
    

    和线程2:

    {
        QMutexLocker lock(&mutex);
        finished=true;
        cond->wakeAll();
    }
    

    这样,如果 thread2 更快,那么在 thread1 到达时 thread2-&gt;finished 已经为真,并且互斥锁在测试它和等待 QWaitCondition 之间保护变量。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-17
      • 2022-01-11
      • 2021-10-10
      相关资源
      最近更新 更多