Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/162.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ Qt-同步线程不工作-线程停止但实际上不工作';t、 有时,当他们不应该的时候,他们也会这样做';T_C++_Multithreading_Qt - Fatal编程技术网

C++ Qt-同步线程不工作-线程停止但实际上不工作';t、 有时,当他们不应该的时候,他们也会这样做';T

C++ Qt-同步线程不工作-线程停止但实际上不工作';t、 有时,当他们不应该的时候,他们也会这样做';T,c++,multithreading,qt,C++,Multithreading,Qt,我有四根线。两个使用OpenCV播放和分析视频,一个保存数据并充当视频和GUI之间的中间人,一个是GUI 我的想法是——视频线程做一些事情,将帧发送给中间人,然后停止自己。如果这是发送的帧对中的第一帧,中间人只会设置一个标志-otherFrame。理论上,由于一个视频停止,现在另一个视频发送一个帧,另一个帧的标志为True,因此中间人将两个帧发送到onPassFramesGui,在onPassFramesGui中,帧放置在qlabel中,然后两个线程都恢复。然后它循环 这是理论,我毫不怀疑这是错

我有四根线。两个使用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

使用这种方法,还可以很容易地为帧添加缓冲区