C++ Qt-同步线程不工作-线程停止但实际上不工作';t、 有时,当他们不应该的时候,他们也会这样做';T
我有四根线。两个使用OpenCV播放和分析视频,一个保存数据并充当视频和GUI之间的中间人,一个是GUI 我的想法是——视频线程做一些事情,将帧发送给中间人,然后停止自己。如果这是发送的帧对中的第一帧,中间人只会设置一个标志-otherFrame。理论上,由于一个视频停止,现在另一个视频发送一个帧,另一个帧的标志为True,因此中间人将两个帧发送到onPassFramesGui,在onPassFramesGui中,帧放置在qlabel中,然后两个线程都恢复。然后它循环 这是理论,我毫不怀疑这是错误的。实际上,分辨率较低的视频很快就会超过另一个。好像它从未停止过 在视频线程中,虽然它们做的事情略有不同,但这是代码的常见部分:C++ Qt-同步线程不工作-线程停止但实际上不工作';t、 有时,当他们不应该的时候,他们也会这样做';T,c++,multithreading,qt,C++,Multithreading,Qt,我有四根线。两个使用OpenCV播放和分析视频,一个保存数据并充当视频和GUI之间的中间人,一个是GUI 我的想法是——视频线程做一些事情,将帧发送给中间人,然后停止自己。如果这是发送的帧对中的第一帧,中间人只会设置一个标志-otherFrame。理论上,由于一个视频停止,现在另一个视频发送一个帧,另一个帧的标志为True,因此中间人将两个帧发送到onPassFramesGui,在onPassFramesGui中,帧放置在qlabel中,然后两个线程都恢复。然后它循环 这是理论,我毫不怀疑这是错
for(nrKlatkiOne=1; nrKlatkiOne<maxFramesOne; nrKlatkiOne++) {
(....)
emit sendFrameOne(imageOne, nrKlatkiOne);
pauseThread();
pause.lock(); //mutex
if(threadPausedOne==true){
pausedCond.wait(&pause); //QWaitCondition
}
pause.unlock();
}
在中间人线程中,这是接收信号的插槽(VideoTwo有一个类似的信号):
我很确定停止线程工作。如果我从其中一个中删除resumeThread(),程序将停止。它将发送第1帧,第2帧->gui,然后是第1帧,然后它将停止
另一种情况是只加载了一个视频,而不是两个。视频线程将在不恢复时随机停止。我有一个信号,显示qDebugs一条消息,在视频停止后,它不会做任何事情(在我更改选项卡时可以恢复),这会导致线程pausedone
/Two
设置为true,然后设置为false
代码编译时没有任何错误或警告
正确的方法是什么?这是我第一次做这种事情
哦,一个额外的问题。是有两个稍微不同的对象更好,还是一个代码多60%的对象只创建多个实例更好?你认为你锁定了互斥锁,没有其他对象可以访问它,但两个线程看起来都改变了布尔值,并尝试锁定互斥锁。不是吗 布尔值已设置,但在互斥锁未立即锁定的情况下可以访问该值
查看Wikipedia的文章。这会有所帮助。你认为你锁定了互斥锁,没有其他线程可以访问它,但这两个线程看起来都改变了布尔值并尝试锁定互斥锁。不是吗 布尔值已设置,但在互斥锁未立即锁定的情况下可以访问该值
查看Wikipedia的文章。这会有所帮助。你认为你锁定了互斥锁,没有其他线程可以访问它,但这两个线程看起来都改变了布尔值并尝试锁定互斥锁。不是吗 布尔值已设置,但在互斥锁未立即锁定的情况下可以访问该值
查看Wikipedia的文章。这会有所帮助。你认为你锁定了互斥锁,没有其他线程可以访问它,但这两个线程看起来都改变了布尔值并尝试锁定互斥锁。不是吗 布尔值已设置,但在互斥锁未立即锁定的情况下可以访问该值
查看Wikipedia的文章。这会有所帮助。无论何时使用共享变量,您都必须锁定互斥锁,用于写入(就像您这样做),也用于读取 例如:
void VideoOne::pauseThread() { //in VideoTwo "One"s are replaced with "Two"s, so the variables are exclusive to their threads
pause.lock(); // lock here
if(threadPausedOne==false){
// pause.lock(); // not here!
threadPausedOne=true;
// pause.unlock(); // not here!
}
pause.lock(); // unlock here
}
void VideoOne::resumeThread() {
pause.lock(); // lock here
if(threadPausedOne==true){
// pause.lock(); // not here!
threadPausedOne=false;
// pause.unlock(); // not here!
pausedCond.wakeAll();
}
pause.lock(); // unlock here
}
对于resumeThread()
,如果在pause
未锁定时必须调用wakeAll,则只需执行此操作。这是您可能必须在其他位置使用的防止死锁的技巧
void VideoOne::resumeThread() {
bool needWakeAll = false;
pause.lock(); // lock here
if(threadPausedOne==true){
threadPausedOne=false;
needWakeAll=true;
}
pause.lock(); // unlock here
if ( needWakeAll )
pausedCond.wakeAll();
}
onSendFrameOne
很可能必须以同样的方式进行修改…无论何时使用共享变量,您都必须锁定互斥锁,以便写入(就像您这样做),也可以读取
例如:
void VideoOne::pauseThread() { //in VideoTwo "One"s are replaced with "Two"s, so the variables are exclusive to their threads
pause.lock(); // lock here
if(threadPausedOne==false){
// pause.lock(); // not here!
threadPausedOne=true;
// pause.unlock(); // not here!
}
pause.lock(); // unlock here
}
void VideoOne::resumeThread() {
pause.lock(); // lock here
if(threadPausedOne==true){
// pause.lock(); // not here!
threadPausedOne=false;
// pause.unlock(); // not here!
pausedCond.wakeAll();
}
pause.lock(); // unlock here
}
对于resumeThread()
,如果在pause
未锁定时必须调用wakeAll,则只需执行此操作。这是您可能必须在其他位置使用的防止死锁的技巧
void VideoOne::resumeThread() {
bool needWakeAll = false;
pause.lock(); // lock here
if(threadPausedOne==true){
threadPausedOne=false;
needWakeAll=true;
}
pause.lock(); // unlock here
if ( needWakeAll )
pausedCond.wakeAll();
}
onSendFrameOne
很可能必须以同样的方式进行修改…无论何时使用共享变量,您都必须锁定互斥锁,以便写入(就像您这样做),也可以读取
例如:
void VideoOne::pauseThread() { //in VideoTwo "One"s are replaced with "Two"s, so the variables are exclusive to their threads
pause.lock(); // lock here
if(threadPausedOne==false){
// pause.lock(); // not here!
threadPausedOne=true;
// pause.unlock(); // not here!
}
pause.lock(); // unlock here
}
void VideoOne::resumeThread() {
pause.lock(); // lock here
if(threadPausedOne==true){
// pause.lock(); // not here!
threadPausedOne=false;
// pause.unlock(); // not here!
pausedCond.wakeAll();
}
pause.lock(); // unlock here
}
对于resumeThread()
,如果在pause
未锁定时必须调用wakeAll,则只需执行此操作。这是您可能必须在其他位置使用的防止死锁的技巧
void VideoOne::resumeThread() {
bool needWakeAll = false;
pause.lock(); // lock here
if(threadPausedOne==true){
threadPausedOne=false;
needWakeAll=true;
}
pause.lock(); // unlock here
if ( needWakeAll )
pausedCond.wakeAll();
}
onSendFrameOne
很可能必须以同样的方式进行修改…无论何时使用共享变量,您都必须锁定互斥锁,以便写入(就像您这样做),也可以读取
例如:
void VideoOne::pauseThread() { //in VideoTwo "One"s are replaced with "Two"s, so the variables are exclusive to their threads
pause.lock(); // lock here
if(threadPausedOne==false){
// pause.lock(); // not here!
threadPausedOne=true;
// pause.unlock(); // not here!
}
pause.lock(); // unlock here
}
void VideoOne::resumeThread() {
pause.lock(); // lock here
if(threadPausedOne==true){
// pause.lock(); // not here!
threadPausedOne=false;
// pause.unlock(); // not here!
pausedCond.wakeAll();
}
pause.lock(); // unlock here
}
对于resumeThread()
,如果在pause
未锁定时必须调用wakeAll,则只需执行此操作。这是您可能必须在其他位置使用的防止死锁的技巧
void VideoOne::resumeThread() {
bool needWakeAll = false;
pause.lock(); // lock here
if(threadPausedOne==true){
threadPausedOne=false;
needWakeAll=true;
}
pause.lock(); // unlock here
if ( needWakeAll )
pausedCond.wakeAll();
}
onSendFrameOne
很可能必须以同样的方式进行修改…您将其过度复杂化,引入了许多标志和同步对象。我建议您在每个视频线程中使用两个QSemaphore
。我将它们命名为allowWork
和hasFrame
视频线程将按如下方式工作:
// Wait until middleman allows work (when it has handled a pair of frames)
allowWork.acquire(1);
// Do frame processing here
// ...
// Tell middleman one frame is ready
hasFrame.release(1);
// Wait until both video threads have a frame
video1.hasFrame.acquire(1);
video2.hasFrame.acquire(1);
// Handle a pair of frames here
// ...
// Tell video threads to make another pair of frames
video1.allowWork.release(1);
video2.allowWork.release(1);
中间人线程将按如下方式工作:
// Wait until middleman allows work (when it has handled a pair of frames)
allowWork.acquire(1);
// Do frame processing here
// ...
// Tell middleman one frame is ready
hasFrame.release(1);
// Wait until both video threads have a frame
video1.hasFrame.acquire(1);
video2.hasFrame.acquire(1);
// Handle a pair of frames here
// ...
// Tell video threads to make another pair of frames
video1.allowWork.release(1);
video2.allowWork.release(1);
在启动代码中,您将把allowWork
初始化为1,并将hasFrame
初始化为0
使用这种方法,还可以很容易地为来自video1和video2的帧添加缓冲区(例如,两个视频线程都工作,直到每个线程都准备了16个帧,而middleman在一对可用时仍然处理),这样您可能会获得更好的线程利用率。您已经将其过度复杂化,引入了许多标志和同步对象。我建议您在每个视频线程中使用两个
QSemaphore
。我将它们命名为allowWork
和hassframe
视频线程将按如下方式工作:
// Wait until middleman allows work (when it has handled a pair of frames)
allowWork.acquire(1);
// Do frame processing here
// ...
// Tell middleman one frame is ready
hasFrame.release(1);
// Wait until both video threads have a frame
video1.hasFrame.acquire(1);
video2.hasFrame.acquire(1);
// Handle a pair of frames here
// ...
// Tell video threads to make another pair of frames
video1.allowWork.release(1);
video2.allowWork.release(1);
中间人线程将按如下方式工作:
// Wait until middleman allows work (when it has handled a pair of frames)
allowWork.acquire(1);
// Do frame processing here
// ...
// Tell middleman one frame is ready
hasFrame.release(1);
// Wait until both video threads have a frame
video1.hasFrame.acquire(1);
video2.hasFrame.acquire(1);
// Handle a pair of frames here
// ...
// Tell video threads to make another pair of frames
video1.allowWork.release(1);
video2.allowWork.release(1);
在启动代码中,您将把allowWork
初始化为1,并将hasFrame
初始化为0
使用这种方法,还可以很容易地为帧添加缓冲区