2014-12-02 76 views
0

我目前的问题是有两个QT线程。其中之一发出一个信号在第二个线程中开始一个操作,然后等待结果。一旦第二个线程完成,第一个线程应该继续使用第二个线程的结果进行自己的操作。解决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

为什么要使用第二个线程,如果你只是想让第一个线程休眠并等待第二个线程完成? – TheDarkKnight 2014-12-02 11:42:22

+0

因为我的第二个线程在另一个类中,所以也应该通过其他几种方式访问​​它。把它放到这个类的函数中,就不可能从其他线程中的其他线程使用它,这些线程也必须等待它。 (AFAIK,这是错的)? – 2014-12-02 11:45:54

+1

线程不驻留在类中。 QThread更像是一个线程控制器。派生自QObject的类可以移动到不同的线程。无论如何,我仍然不明白为什么你需要创建第二个线程。线程允许并发处理,根据你的描述,你的应用程序没有使用这个。如果您发布了问题的示例代码,您可能会收到更好的回复,并且缺乏这可能是为什么有人(而不是我)决定降低您的问题的原因。 – TheDarkKnight 2014-12-02 13:57:08

回答

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); 
    } 
} 

及线程:

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

那样如果thread2更快然后thread2->finished已经是真的b y thread1到达的时间,互斥量在测试和等待QWaitCondition之间保护变量。

0

也许Qt::BlockingQueuedConnection是你需要什么?

阻塞排队连接就像是一个排队连接,但发送者线程阻塞,直到事件被接收者所在线程的事件循环拾取为止,该槽被调用并返回;