音频线程
Audio threading
我的应用程序中有一个单独的音频线程,因为这在当时听起来是个好主意,但现在我不知道其他线程将如何与音频线程通信。
audioThread() {
while(!isCloseRequested) {
If(audio.dogSoundRequested) {
audio.playDogSound();
}
}
}
otherThread() {
Audio.dogSoundRequested();
}
这是一种有效的音频线程方式吗?或者你看到这个设置有问题吗?
这里的关键问题似乎是
1:如何使audio.dogSoundRequested
和isCloseRequested
线程安全。
2:audioThread
正忙于等待(例如无限旋转直到audio.dogSoundRequested
变为true
。
正如其他人所建议的那样,您可以使用互斥来保护这两个变量,但这太过分了——此外,在音频代码中,为了避免优先级反转问题,不使用阻塞同步通常是一种很好的形式。
相反,假设您使用的是C++11或C++14,您可以使用原子变量,这些变量是轻量级的,并且(在大多数实现中)不会阻塞:
#include <atomic>
...
std::atomic<bool> dogSoundRequested{false};
std::atomic<bool> isCloseRequested{false};
对std::atomic的读取和写入与内置类型具有相同的约定,但将生成代码,以确保读取和写入相对于其他线程是原子的,并且结果与其他CPU同步。
在audio.dogSoundRequested
的情况下,您想要这两种效果,而在isCloseRequested
的情况中,结果在其他CPU上立即可见。
要解决忙等待问题,请使用条件变量在有事情要做时唤醒audioThread
:
#include <condition_variable>
std::mutex m;
std::condition_variable cv;
audioThread()
{
while(!isCloseRequested)
{
m.lock();
cv.wait(m);
// wait() returns with the mutex still held.
m.unlock();
if(audio.dogSoundRequested)
{
audio.playDogSound();
}
}
}
void dogSoundRequested()
{
dogSoundRequested = true;
cv.notify_one();
}
除了使用互斥,这里还有一个用于多线程的简单设置
// g++ -o multi_threading -pthread -std=c++11 multi_threading.cpp
#include <iostream>
#include <thread>
#include <exception>
#include <mutex>
#include <climits> // min max of short int
void launch_consumer() {
std::cout << "launch_consumer" << std::endl;
} // launch_consumer
void launch_producer(std::string chosen_file) {
std::cout << "launch_producer " << chosen_file << std::endl;
} // launch_producer
// -----------
int main(int argc, char** argv) {
std::string chosen_file = "audio_file.wav";
std::thread t1(launch_producer, chosen_file);
std::this_thread::sleep_for (std::chrono::milliseconds( 100));
std::thread t2(launch_consumer);
// -------------------------
t1.join();
t2.join();
return 0;
}
与其用互斥和条件变量使代码复杂化,不如考虑制作一个线程安全的FIFO。在这种情况下,可能有多个作者和一个消费者。应用程序的其他线程是该FIFO的写入程序,audioThread()
是消费者。
// NOP = no operation
enum AudioTask {NOP, QUIT, PLAY_DOG, ...};
class Fifo
{
public:
bool can_push() const; // is it full?
void push(AudioTask t); // safely writes to the FIFO
AudioTask pop(); // safely reads from the FIFO, if empty NOP
};
现在,假设fifo
和audio
是应用程序类成员,audioThread()
就更干净了:
void audioThread()
{
bool running = true;
while(running)
{
auto task = fifo.pop();
switch(task)
{
case NOP: std::this_thread::yield(); break;
case QUIT: running = false; break;
case PLAY_DOG: audio.playDogSound(); break;
}
}
}
最后,调用代码只需要将任务推入FIFO:
void request_dog_sound()
{
fifo.push(PLAY_DOG);
}
void stop_audio_thread()
{
fifo.push(QUIT);
audio_thread.join();
}
这将线程安全同步的细节放在Fifo类中,使应用程序的其余部分更干净。
如果要确保没有其他线程接触playDogSound()
函数,请使用互斥锁来锁定资源。
std::mutex mtx;
audioThread() {
while(!isCloseRequested) {
if (audio.dogSoundRequested) {
mtx.lock();
audio.playDogSound();
mtx.unlock();
}
}
}
- 从不同线程使用int64的不同字节安全吗
- 删除一个线程上有数百万个字符串的大型哈希映射会影响另一个线程的性能
- 在C++中使用cURL和多线程
- 为什么我的C#代码在调用回C++COM直到Task时会暂停.等待/线程.加入
- 在cuda线程之间共享大量常量数据
- 如何将元素添加到数组的线程安全函数?
- 线程,如果else语句,都是错误的上下文切换后,会发生什么
- C++Boost Asio Pool线程,带有lambda函数和传递引用变量
- Qt C++静态thread_local QNetworkAccessManager是线程应用程序的好选择吗
- 异常属于C++中的线程还是进程
- C++中的线程安全删除
- C++使用params创建线程函数会导致转换错误
- 类与私有变量的其他类之间的线程安全性
- CoInitialize()在单独的线程上崩溃而不返回
- 使用FFMPEG编写多线程视频和音频数据包
- 音频线程
- 什么是Qt中低延迟音频合成的最佳多线程方法
- 我什么时候需要一个无锁的数据结构来跨音频应用程序中的线程读取/写入数据
- 如何使一个线程在MFC中移动滑块控件相对于正在播放的音频文件
- 关闭音频时线程很慢