Multithreading at start()调用线程仍在运行时的QThread状态,但之后的状态已不存在

Multithreading at start()调用线程仍在运行时的QThread状态,但之后的状态已不存在,multithreading,qt,qthread,qmutex,Multithreading,Qt,Qthread,Qmutex,我有一个GUI线程,我在其中调用另一个MyQThread方法的write(QString text) MyQthread包含QMutex互斥体和QList列表。下面是MyQThread的write()和run()方法: void MyQThread::write(QString text) { mutex.lock(); list.append(text); //Point C mutex.unlock(); start(); //Point D }

我有一个GUI线程,我在其中调用另一个
MyQThread
方法的
write(QString text)
MyQthread
包含
QMutex互斥体
QList列表
。下面是
MyQThread
write()
run()
方法:

void MyQThread::write(QString text)
{
     mutex.lock();
     list.append(text); //Point C
     mutex.unlock();
     start(); //Point D
}  

void MyQThread::run()
{
     mutex.lock();

     while(!list.isEmpty())
     {
         QString text = list.takeFirst();
         mutex.unlock();
         ...//do something
         mutex.lock(); //Point A
     }

     mutex.unlock(); //Point B
}  
例如,我们处于“A点”。在这一点之后,我们正在检查列表,它是空的,因此我们将进入“点B”。此时调用
write()
,互斥锁仍处于锁定状态,因此GUI线程在“C点”之前等待。
现在我们到了“点B”,在这个GUI线程被解锁并调用start()(“点D”)之后。
是否可能在“点D”MyQThread仍在运行?
在这种情况下,调用
start()
什么都不做。在下一次调用
write()


补充资料。在我的例子中,这里只有一个MyQThread实例。

QThread的方法是'isRunning'和'isFinished'。因此可以查询线程状态。当然,您的线程可能仍在“D点”运行

但你真的应该停下来读点书。 和


当然还有Qt文档中关于QMutexLocker的内容。

是的。尽管出现竞争条件的概率很低,但我相信QThread仍有可能发送信号等等。请在调用
start()
之前使用

编辑:同意需要考虑的问题。这些代码很快就会变得非常复杂,你不能确定你会记得在每个出口点解锁


编辑2:也许a对你的情况更有趣?

@Alexism谢谢你的想法。这个解决方案怎么样:

class MyQThread:
    public: QThread
{
    ...
    QList<QString> list;
    QMutex mutex;
    QWaitCondition listNotEmpty;
}

void MyQThread::write(QString text)
{
     QMutexLocker locker(&mutex);
     list.append(text);
     listNotEmpty.wakeAll();
}  

void MyQThread::run()
{
     forever
     {
         mutex.lock();
         if(list.isEmpty())
             listNotEmpty.wait(&mutex);

         if(list.isEmpty())
         {
             mutex.unlock();
             continue;
         }
         QString text = list.takeFirst();
         mutex.unlock();
         ...//do something
     }
}  
类MyQThread:
公共:QThread
{
...
QList列表;
QMutex互斥;
qwaitconditionlistnotempty;
}
void MyQThread::write(QString文本)
{
QMutexLocker锁柜(&mutex);
列表。追加(文本);
listNotEmpty.wakeAll();
}  
void MyQThread::run()
{
永远
{
mutex.lock();
if(list.isEmpty())
listNotEmpty.wait(&mutex);
if(list.isEmpty())
{
mutex.unlock();
继续;
}
QString text=list.takeFirst();
mutex.unlock();
…做点什么
}
}  
那么
wait()
-
unsigned long time=ULONG_MAX
的第二个参数呢
在我的例子中,如果长时间没有调用
write()
方法,并且
wait()
将在
run()
ULONG\u MAX
之后返回
false
,那么它似乎不会出错。在这种情况下,我需要再次等待

在文件中写着:

互斥锁将返回到相同的锁定状态


这是否意味着,即使在
wait()
wait()
之前未锁定互斥锁,互斥锁也将始终在
wait()
之后锁定?QMutexLocker将锁定GUI线程(在“点C”之前),直到
run()
完成(对吗?)。我想在运行
run()
时将项目附加到列表中。实际上,您不能只使用这些状态,因为它们可能是从线程本身设置的,因此当
isFinished()返回false时,线程可能仍在运行。您需要将状态检查与调用
wait()
结合起来才能确定。小错误:我的意思是“when isFinished()返回true”。我只想锁定MyQThread,避免锁定GUI线程。在
QThread::wait()的情况下,
GUI将被锁定,直到MyQthread完成。我的观点是,从点B到线程完成之间的时间应该非常短。在GUI线程中使用
QThread::wait()
,可以为主事件循环提供处理连接到线程的任何信号和插槽所需的少量时间。它不应该长时间锁定。@Funt重新启动线程可能仍然会锁定GUI线程,具体取决于系统负载。你不能让线程保持运行但锁定吗?由于您的问题基本上是一个“生产者-消费者”问题,
QWaitCondition
可能会有所帮助(文档中也有)。@alexisdm在我看来,您刚刚提出了最明智的建议。@alexisdm是的,您是对的。但在本例中,线程一直在运行,直到数据大小被处理。在我的例子中,我需要使用
start()
while(!list.isEmpty())
甚至使用
QWaitCondition
。这将导致同样的问题:(也许我可以将
while(!list.isEmpty())
替换为
forever
并调用
start()
只有一次。这会解决我的问题。但我不确定这是否是个好主意。
ULONG_MAX
是一个特殊值,不作为时间计算,例如,在Windows上,它对应于传递给
WaitForSingleObject
无限值(请参阅),因此wait在这种情况下不会返回
false
。由于无法解锁已解锁的互斥锁,并且
wait()
在实际等待之前确实解锁了互斥锁,因此应始终在
wait()之前锁定互斥锁
。即使wait返回false,互斥锁也会在锁定状态下返回。您还应该编辑答案,以更清楚地说明
listNotEmpty
是一个
QWaitCondition