我需要在CoreAudio的实时线程和UI线程之间传递数据(单向,RT-> UI)。我知道我不能使用任何Cocoa / Objective C方法,如performSelectorOnMainThread
或NSNotification
,我不能使用任何会分配内存的东西,因为这可能会阻止RT线程。
线程之间进行通信的正确方法是什么?我可以使用GCD消息队列还是有更基本的系统可供使用?
编辑:
考虑到这一点,我想我可以使用无锁环缓冲区,RT线程将消息放入其中,并且UI线程检查要拔出的消息。这是最好的方法,如果有的话,系统已经在CoreAudio中执行此操作或在其他地方可用,或者我是否需要自己编写代码?
答案 0 :(得分: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);
最后,我每隔20ms开始一次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);
}
然后在实时线程中,将消息推送到ringbuffer只是
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);
}
答案 1 :(得分:2)
一个环形缓冲区是一个很好的解决方案。两个如果你需要两种方式沟通,即。收件箱/发件箱消息传递。
如果您不想使用Portaudio,这是iOS / Mac的一个很好的实现。