【发布时间】:2018-08-03 08:35:22
【问题描述】:
我正在编写一个 Audio 类,其中包含一个 std::thread 用于异步重新填充一些缓冲区。假设我们调用主线程 A 和后台(类成员)线程 B。我正在使用 std::mutex 来阻止线程 B 每当声音没有播放时,这样它就不会在不必要时在后台运行并且不会不要使用过多的 CPU 资源。默认情况下,线程 A 锁定了互斥锁,因此线程 B 被阻塞,然后当播放声音时,线程 A 解锁互斥锁,线程 B 循环运行(通过锁定然后立即解锁)。
当线程 B 发现它已到达文件末尾时,问题就出现了。它可以停止播放和清理缓冲区等,但它不能停止自己的循环,因为线程 B 无法锁定线程 A 的互斥锁。
以下是相关代码大纲:
class Audio {
private:
// ...
std::thread Thread;
std::mutex PauseMutex; // mutex that blocks Thread, locked in constructor
void ThreadFunc(); // assigned to Thread in constructor
public:
// ...
void Play();
void Stop();
}
_
void Audio::ThreadFunc() {
// ... (include initial check of mutex here)
while (!this->EndThread) { // Thread-safe flag, only set when Audio is destructed
// ... Check and refill buffers as necessary, etc ...
if (EOF)
Stop();
// Attempt a lock, blocks thread if sound/music is not playing
this->PauseMutex.lock();
this->PauseMutex.unlock();
}
}
void Audio::Play() {
// ...
PauseMutex.unlock(); // unlock mutex so loop in ThreadFunc can start
}
void Audio::Stop() {
// ...
PauseMutex.lock(); // locks mutex to stop loop in ThreadFunc
// ^^ This is the issue here
}
在上面的设置中,当后台线程看到它到达 EOF 时,它会调用类的 Stop() 函数,该函数应该锁定互斥体以停止后台线程。这不起作用,因为互斥锁必须由主线程而不是后台线程锁定(在此示例中,它在 ThreadFunc 中崩溃,因为后台线程在锁定 @987654330 后尝试在其主循环中锁定@)。
此时我唯一能想到的就是让后台线程以某种方式锁定互斥锁就好像它是主线程,让主线程拥有互斥锁...如果这可能吗?线程有没有办法将互斥锁的所有权转移给另一个线程?或者这是我创建的设置中的设计缺陷? (如果是后者,是否有任何合理的解决方法?)到目前为止,课堂上的其他所有内容都按设计工作。
【问题讨论】:
-
这是乞求基于RAII 的锁定方案。我同意上述观点。这需要一些真正的谓词数据、一个保护该数据的互斥体,以及一个表示该数据潜在状态变化的条件变量。如果您发现自己使用
std::mutex类手动调用lock和unlock,而这所有您似乎都在做,那么您可能做错了什么。 -
@user463035818 那不需要主线程反复检查它是否应该调用
Stop()? -
您已经在循环中反复锁定和解锁互斥锁。有一个循环
while(running) { ...更自然,其中running可以由任一线程设置 -
互斥锁在后台线程中反复被锁定和解锁,同时主线程可能正忙于其他完全不相关的任务
标签: c++ multithreading mutex