3

我需要在 CoreAudio 的实时线程和 UI 线程之间传递数据(一种方式,RT-> UI)。我知道我不能使用任何 Cocoa/Objective C 方法,例如performSelectorOnMainThreadorNSNotification并且我不能使用任何会分配内存的东西,因为这可能会阻塞 RT 线程。

线程之间通信的正确方法是什么?我可以使用 GCD 消息队列还是可以使用更基本的系统?

编辑:

再想一想,我想我可以使用无锁环形缓冲区,RT 线程将消息放入其中,UI 线程检查要提取的消息。这是最好的方法吗?如果是这样,CoreAudio 中是否已经有一个系统可以做到这一点或在其他地方可用,还是我需要自己编写代码?

4

2 回答 2

2

事实证明这比我预期的要简单得多,我想出的解决方案就是使用 Portaudio 环形缓冲区。我需要将 pa_ringbuffer.[ch] 和 pa_memorybarrier.h 添加到我的项目中,然后定义一个 MessageData 结构以存储在环形缓冲区中。

typedef struct MessageData {
    MessageType type;
    union {
        struct {
            NSUInteger position;
        } position;
    } data;
} MessageData;

然后我分配了一些空间来存储 32 条消息并创建了环形缓冲区。

_playbackData->RTToMainBuffer = malloc(sizeof(MessageData) * 32);
PaUtil_InitializeRingBuffer(&_playbackData->RTToMainRB, sizeof(MessageData),
                            32, _playbackData->RTToMainBuffer);

最后,我每 20 毫秒启动一个 NSTimer 从环形缓冲区中提取数据

while (PaUtil_GetRingBufferReadAvailable(&_playbackData->RTToMainRB)) {
    MessageData *dataPtr1, *dataPtr2;
    ring_buffer_size_t sizePtr1, sizePtr2;

    // Should we read more than one at a time?
    if (PaUtil_GetRingBufferReadRegions(&_playbackData->RTToMainRB, 1,
                                        (void *)&dataPtr1, &sizePtr1,
                                        (void *)&dataPtr2, &sizePtr2) != 1) {
        continue;
    }

    // Parse message
    switch (dataPtr1->type) {
        case MessageTypeEOS:
            break;

        case MessageTypePosition:
            break;

        default:
            break;
    }
    PaUtil_AdvanceRingBufferReadIndex(&_playbackData->RTToMainRB, 1);
}

然后在实时线程中,将消息推送到环形缓冲区很简单

MessageData *dataPtr1, *dataPtr2;
ring_buffer_size_t sizePtr1, sizePtr2;

if (PaUtil_GetRingBufferWriteRegions(&data->RTToMainRB, 1,
                                     (void *)&dataPtr1, &sizePtr1,
                                     (void *)&dataPtr2, &sizePtr2)) {
    dataPtr1->type = MessageTypePosition;
    dataPtr1->data.position.position = currentPosition;

    PaUtil_AdvanceRingBufferWriteIndex(&data->RTToMainRB, 1);
} 
于 2013-03-23T12:53:49.087 回答
2

环形缓冲区是一个很好的解决方案。如果您需要两种方式进行交流,请使用两个,即。收件箱/发件箱消息传递。

如果您不想使用 Portaudio,这对于 iOS/Mac 来说是一个很好的实现。

https://github.com/michaeltyson/TPCircularBuffer

于 2015-02-15T12:07:13.177 回答