音频线程

时间:2014-10-31 17:59:00

标签: c++ multithreading audio

我的应用程序中有一个单独的音频线程,因为它在当时听起来是个好主意,但现在我对其他线程如何与音频线程进行通信感到惋惜。

audioThread() {

while(!isCloseRequested) {

If(audio.dogSoundRequested) {

audio.playDogSound();
        }
    }
}

otherThread() {

Audio.dogSoundRequested();

}

这是一种有效的线程音频方式,还是您看到此设置存在问题?

4 个答案:

答案 0 :(得分:0)

除了使用互斥锁之外,这里还有一个简单的多线程设置

//  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;
}

答案 1 :(得分:0)

这里的问题似乎是

1:如何使audio.dogSoundRequestedisCloseRequested线程安全。

2:audioThread正忙着等待(例如无限旋转,直到audio.dogSoundRequested变为true

正如其他人所建议的那样,你可以使用互斥锁来保护这两个变量,但这样做太过分了 - 另外,它通常是音频代码的好形式,不使用阻塞同步来避免priority inversion的问题。 / p>

相反,假设你正在使用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();
}

答案 2 :(得分: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
};

现在audioThread()更清晰一点,假设fifoaudio是应用程序类成员:

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类中,使应用程序的其余部分保持清洁。

答案 3 :(得分:-1)

如果您想确保没有其他线程触及playDogSound()函数,请使用互斥锁来锁定资源。

std::mutex mtx;

audioThread() {
    while(!isCloseRequested) {
        if (audio.dogSoundRequested) {
            mtx.lock();
            audio.playDogSound();
            mtx.unlock();
        }
    }
}