【发布时间】:2015-02-27 13:58:57
【问题描述】:
免责声明:我前几天问过这个问题on codereview,但没有得到答案。这里我将问题格式从review request改为具体问题。
我正在开发一个具有以下设计的视频播放器:
主线程 - 是 GUI 线程(Qt SDK)。
第二个线程 - 播放器线程,它接受来自 GUI 线程的命令来播放、前进、后退、停止等。现在,这个线程在一个恒定循环中运行,并使用互斥锁和等待条件与主线程命令同步.
这段代码有两个问题:
我不觉得我的设计是完全正确的:我同时使用互斥锁和原子变量。我想知道我是否可以只使用原子并且只使用锁来设置等待条件。
当我运行“播放”命令时,我遇到了不一致的错误(可能是由于在播放循环工作时播放命令尝试锁定已被线程锁定的互斥锁时的条件竞争)线程循环。所以我想它会阻止对主线程的共享变量的访问。
我已经从不需要的东西中剥离了代码,它通常是这样的:
void PlayerThread::drawThread()//thread method passed into new boost::thread
{
//some init goes here....
while(true)
{
boost::unique_lock<boost::mutex> lock(m_mutex);
m_event.wait(lock); //wait for event
if(!m_threadRun){
break; //exit the tread
}
///if we are in playback mode,play in a loop till interrupted:
if(m_isPlayMode == true){
while(m_frameIndex < m_totalFrames && m_isPlayMode){
//play
m_frameIndex ++;
}
m_isPlayMode = false;
}else{//we are in a single frame play mode:
if(m_cleanMode){ ///just clear the screen with a color
//clear the screen from the last frame
//wait for the new movie to get loaded:
m_event.wait(lock);
//load new movie......
}else{ //render a single frame:
//play single frame....
}
}
}
}
以下是上述类的成员函数,它们向线程循环发送命令:
void PlayerThread::PlayForwardSlot(){
// boost::unique_lock<boost::mutex> lock(m_mutex);
if(m_cleanMode)return;
m_isPlayMode = false;
m_frameIndex++;
m_event.notify_one();
}
void PlayerThread::PlayBackwardSlot(){
// boost::unique_lock<boost::mutex> lock(m_mutex);
if(m_cleanMode)return;
m_isPlayMode = false;
m_frameIndex-- ;
if(m_frameIndex < 0){
m_frameIndex = 0;
}
m_event.notify_one();
}
void PlayerThread::PlaySlot(){
// boost::unique_lock<boost::mutex> lock(m_mutex);
if(m_cleanMode)return;
m_isPlayMode = true;
m_event.notify_one(); //tell thread to start playing.
}
m_cleanMode、m_isPlayMode 和 m_frameIndex 等所有标志成员都是原子的:
std::atomic<int32_t> m_frameIndex;
std::atomic<bool> m_isPlayMode;
std::atomic<bool> m_cleanMode;
问题总结::
使用原子时是否需要互斥锁?
我是否在 while 循环内的正确位置设置了等待 线?
有什么更好的设计建议吗?
更新:
虽然我得到的答案似乎是正确的方向,但我并不真正理解它。尤其是讨论服务的伪代码部分。我完全不清楚它是如何工作的。我想要得到一个更详细的答案。同样奇怪的是,对于这样一个常见问题,我只收到了一个建设性的答案。所以我正在重置赏金。
【问题讨论】:
-
Michael,如果你不知道 qt 有自己的互斥量、条件等类,例如
QMutex、QReadWriteLock、QWaitCondition -
另外,在 qt 中,您可以跨线程发送信号,这在某些情况下可以帮助完全避免使用锁
-
@InnocentBystander 是的,我知道,但我已经在使用 Boost 线程 API,并且没有时间正确学习 Qt 的相关 API。
-
几年前我在windows中使用c做了同样的事情(播放mp3文件,我自己解码)。我有三个线程:主 gui,处理来自 gui 的消息,解码 mp3。多线程的诀窍是尽可能多地隔离线程。隔离的所有变量(这是我避免问题的主要目标)并且我只有一个锁:从消息队列写入和读取。写入是从主 gui 执行的,读取是从线程处理消息中执行的。
-
队列是一个结构数组。每个结构都有关于要执行什么的信息,例如播放、停止、暂停、下一首歌曲、歌曲标题等。主 gui 向队列中添加了一条新消息,处理线程删除了这些消息。它没有任何问题,主要是因为我没有共享变量。只有一把锁。希望对您有所帮助。
标签: c++ multithreading qt