waveOut (Win32API) и многопоточность
Я не могу найти информацию о безопасности потоков API waveOut.
После того, как я создал новый дескриптор waveOut, у меня есть эти потоки:
Поток 1: Обработка буферов. Использует эти функции API:
- waveOutPrepareHeader
- waveOutWrite
- waveOutUnprepareHeader
Нить 2: Gui, Нить контроллера. Использует эти функции API:
- waveOutPause
- waveOutRestart
- waveOutReset
- waveOutBreakLoop
Эти два потока работают при одновременном использовании одного и того же дескриптора waveOut. В своих тестах я не видел никаких проблем с функциональностью, но это не значит, что она безопасна.
Является ли эта архитектура поточно-ориентированной? Есть ли документация по безопасности потоков API waveOut? Какие-либо другие предложения по безопасности потоков API WaveOut?
Благодарю.
4 ответа
В общем случае API waveOut должен быть ориентирован на многопотоковое исполнение. Потому что обычно waveOutOpen() создает свой собственный поток, и все функции waveOut* отправляют сообщения в этот поток. Но я не могу дать вам доказательства...
Тем не менее, вы можете изменить свое приложение, чтобы сделать его безопасным в любом случае:
- запустите ваш поток для управления буфером, запомните dwBufferThreadId
- из потока графического интерфейса вызовите waveOutOpen, для которого dwCallback имеет значение dwBufferThreadId, а fdwOpen - CALLBACK_THREAD
- ваш поток управления буфером: "waveOutWrite" заранее несколько буферов, цикл на GetMessage ()
- waveOutOpen будет отправлять WOM_DONE всякий раз, когда буфер завершается и требуется новый буфер, в этот момент waveOutWrite новый буфер из этого потока
- Сделайте ваши вызовы waveOutPause, waveOutRestart и так далее из потока GUI (ничего в MSDN не говорит против этого, и все примеры делают это, даже если буферы будут заполнены из другого потока)
Если вы хотите быть на 100% уверены, вы можете просто получить сообщение Windows (WM_USER+0) и позвонить PostThreadMessage( WM_USER+0, dwBufferThreadId, MY_CTL_PAUSE,0 )
а затем, получив это сообщение в буфере потока, вы вызываете waveOutPause()
там. Очереди сообщений Windows избавят вас от необходимости писать собственные очереди сообщений;-)
К сожалению, это небезопасно даже в однопоточной среде. Посмотрите на этот вопрос для обсуждения:
Почему waveOutWrite() вызывает исключение в куче отладки?
Попытки сообщить об этом в Microsoft привели к закрытию ошибки. Они не собираются это исправить.
Я также не видел никакой документации, но я не могу себе представить, что вызов waveOutWrite будет считаться безопасным для одновременного выполнения с вызовом WaveOutRestart для того же дескриптора.
Если вы используете VS2010 Beta2, я бы посмотрел на различные пошаговые руководства для библиотеки агентов и попытался превратить ее в проблему потребителя производителя, когда вы передаете сообщения, такие как запись, пауза, перезапуск и т. Д.
Если вы не используете Visual Studio 2010 (или не можете), я бы посоветовал вам найти способ разбить это на проблему потребителя производителя, используя потоки и какую-то внутреннюю синхронизированную очередь, в которой хранятся команды для обработки. Если сообщения не такие частые и учитывая, что в этой очереди работают только 2 потока, вы можете избежать использования простого старого критического раздела Win32 вокруг std::queue...
надеюсь это поможет.
Это может быть потокобезопасным, но если вы (или я) не можете найти официальную документацию, утверждающую, что это потокобезопасный, то предположите, что это не так и добавьте свою собственную синхронизацию потоков. Легкая реализация EnterCriticalSection / LeaveCriticalSection, вероятно, занимает не более десятка строк кода.
Никакое количество испытаний не может гарантировать, что API является поточно-ориентированным: проблемы могут возникать только на некоторых архитектурах с некоторыми скоростями процессора или шины или с некоторыми звуковыми картами. Ни у вас (ни у Microsoft) нет возможности протестировать все возможные конфигурации.
Вы также не должны делать никаких предположений о том, что Microsoft или Intel, или производитель звуковых карт, или драйвер будут делать в будущем.