Конечно, есть очереди без блокировки. Однако, исходя из того, что вы сказали в комментариях, производительность здесь совсем не критична, так как вы все равно создаете поток для каждой записи.
Итак, это стандартный вариант использования условной переменной. Создайте себе структуру, содержащую мьютекс, переменную условия, связанный список (или кольцевой буфер, если хотите) и флаг отмены:
write:
lock the mutex
(optionally - check the cancel flag to prevent leaks of stuff on the list)
add the event to the list
signal the condition variable
unlock the mutex
read:
lock the mutex
while (list is empty AND cancel is false):
wait on the condition variable with the mutex
if cancel is false: // or "if list non-empty", depending on cancel semantics
remove an event from the list
unlock the mutex
return event if we have one, else NULL meaning "cancelled"
cancel:
lock the mutex
set the cancel flag
(optionally - dispose of anything on the list, since the reader will quit)
signal the condition variable
unlock the mutex
Если вы используете список с внешними узлами, вы можете выделить память вне блокировки мьютекса, просто чтобы сократить время, в течение которого она удерживается. Но если вы создаете события с помощью навязчивого узла списка, это, вероятно, проще всего.
Редактировать: вы также можете поддерживать несколько считывателей (без переносных гарантий, для которых вы получаете данное событие), если при отмене вы меняете «сигнал» на «трансляцию». Хотя вам это не нужно, на самом деле это тоже ничего не стоит.