线程新手遇到线程失控问题
好吧,为了你明白我会解释这个问题: 我正在使用一个名为 ClanLIB 的库(不是我的选择),该库似乎(我不确定,甚至阅读源代码)创建了一个处理声音的线程。
当缓冲区为空时,该线程尝试获取更多数据,通常当数据生成库太慢而无法在声卡到达缓冲区末端之前提供更多数据时,这会导致欠载运行。
所以我添加了自己的线程,它不断在后台生成声音。
这工作得很好,只是我自己的线程有时会劫持太多的 CPU 时间并冻结其他所有内容。为了解决这个问题,我添加了条件等待。
当缓冲区已满时,会发生条件等待,并且当 ClanLIB 请求更多数据时,会发出等待信号,从而恢复缓冲区写入线程(直到再次满)。
我的问题是,由于我添加了这个条件等待、ClanLIB 声音线程和我自己的音乐线程,有时会“失控”,在应用程序的其余部分冻结时播放音乐。
什么样的奇怪情况会导致这种情况?
伪代码:
//main thread (that get frozen)
start_sound_thread();
do_lots_of_stuff();
quit();
//Sound Thread:
While(true)
{
play(buffer);
if(buffer_empty)
{
mutex.lock()
buffer = buffer2;
if(buffer2_full)
{
signal(cond1);
buffer2_full = false;
}
mutex.unlock()
}
}
//Music Library Thread:
while(true)
{
mutex.lock()
if( check_free_space(buffer2) == 0)
{
buffer2_full = true;
condition_wait(cond1);
}
write_music(buffer2);
mutex.unlock()
}
Ok, to you understand I will explain the problem:
I am using a library called ClanLIB (not my choice), that library, SEEMLY (I am not certain, even reading the sourcE), creates a thread that handles sound.
This thread, when the buffer is empty, tries to fetch more data, usually this cause a underrun when the data generating library is too slow to give more data before the soundcard reaches the buffer end.
So I added my own thread, that keeps generating sound on the background.
This worked fine, except that my own thread sometimes hijacked too much CPU time and froze everything else. To fix it, I added a conditional wait.
The conditional wait happens when the buffer is full, and when ClanLIB ask for more data, the wait is signaled, thus the buffer write thread resumes (until it is full again).
My issue is that since I added this conditional wait, the ClanLIB sound thread, and my own music thread, SOMETIMES get "runaway", playing music while the rest of the application freezes.
What sort of strange condition would cause that?
pseudocode:
//main thread (that get frozen)
start_sound_thread();
do_lots_of_stuff();
quit();
//Sound Thread:
While(true)
{
play(buffer);
if(buffer_empty)
{
mutex.lock()
buffer = buffer2;
if(buffer2_full)
{
signal(cond1);
buffer2_full = false;
}
mutex.unlock()
}
}
//Music Library Thread:
while(true)
{
mutex.lock()
if( check_free_space(buffer2) == 0)
{
buffer2_full = true;
condition_wait(cond1);
}
write_music(buffer2);
mutex.unlock()
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
您在互斥区域内做了太多的事情 - 很可能您在 cond1 信号上陷入僵局。您应该在锁定区域内尽可能少地执行操作,因为您执行的操作越多,引入死锁的风险就越大 - 并且您绝对不应该等待保护信号发送的互斥体内部的信号 - 如果您'正在等待,它永远不会被发送 - condition_wait 不会解锁您的互斥对象,它怎么可能知道这一点?
“通过添加条件等待解决”是一个强有力的指标,表明您存在导致死锁的竞争条件 - 一旦逻辑的执行时间因任何原因发生变化(例如因为另一个应用程序),您就没有解决问题正在运行时,死锁可能会返回。
You're doing WAY too much within the mutex zones - it's likely you are deadlocking on the cond1 signal. You should do as little as possible within locking regions, because the more you do, the more risk you will introduce a deadlock - and you absolutely should never wait on a signal inside of a mutex that guards the sending of the signal - if you're waiting, it isn't ever going to be sent - condition_wait is not unblocking your mutex object, how could it know about it ?
The 'solved by addition of conditional waits' is a strong indicator you've got a race condition leading to deadlock - you haven't solved the problem, as soon as the execution timing of your logic changes for any reason, say because another app is running, the deadlock can return.
我也在一个项目中使用 clanlib,但使用 OpenAL 来处理声音。它似乎与馈送缓冲区等的工作方式相同。
我还使用单独的线程来处理声音,但我的解决方案是在每次尝试馈送缓冲区后添加一个固定的睡眠时间。它很简单,而且看起来相当可靠。并且不需要锁定;)
I'm using clanlib for a project too, but using OpenAL for sound. It seems to work the same way with feeding the buffer etc.
I also use a seperate thread for sound, but my solution was to just add a fixed sleep period after each attempt to feed the buffer. It's simple and seems pretty solid. And no locking is required ;)
实际上,我不知道问题是什么,它是偶然修复的...
我有一个相关的问题,这是由删除线程时的竞争条件引起的...我移动了一些代码(我不甚至需要重新编码任何东西)并且它也消失了。现在事情已经完全稳定了! (好吧,仍然有欠载,但现在更加罕见)
I actually, don't know what the issue was, it was fixed by accident...
I had a related issue, this one was caused by race condition when deleting the thread... I moved some code around (I don't even needed to recode anything) and it went away too. Now the thing is perfectly stable! (well, still has underruns but they are more rare now)
如果您使用 ClanLib 游戏 SDK,那么它是一个完善、经过测试且受支持的 SDK。无意冒犯,但是,由于您是公认的新手,问题更有可能出现在您的代码中,而不是他们的代码中。
我发现很难相信这样一个完善的库会出现欠载运行,即使确实如此,我怀疑最好的解决方案是
添加我自己的线程,它会在后台不断生成声音< /代码>。我这样说是因为我怀疑您采取了错误的方法,并且如果您可以使用 ClanLib 找到解决方案,那么您将不需要您的线程和线程。你的问题将会消失,无需解决。
您发布代码真是太好了,谢谢。我现在就去看看。
最后,作为我的忠实粉丝,最好先在官方 ClanLib 论坛 首先?
编辑:是什么让你如此确定这是一个欠载?我仍然觉得很难相信,但如果你可以在程序中检测到它,那么为什么不使用
sleep()
,而不是生成声音呢? (睡多长时间?你怎么知道要产生多少声音?产生的声音不会干扰“真实”声音吗?)If you are using ClanLib game SDK it is a well establish, tested and supported SDK. No offence intended, but, as you are an admitted newbie, the problem is more likely in your code than theirs.
I find it difficult to believe that such a well established library would develop an underrun, and, even if it it does, I doubt that the best solution would be to
added my own thread, that keeps generating sound on the background
. I say this because I suspect that you are taking the wrong approach and that if you can find a solution with ClanLib then you won't need your thread & your problem will be gone without needing to be solved.It is goo that you posted code, thanks. I'll go off and look at that now.
And, finally, as great a fan as I am of SO, wouldn't it be better to ask first at the official ClanLib forum first?
Edit: what makes you so sure it is an underrun? i still find that hard to believe, but if you cna detect it in your program, then why not
sleep()
, rather than generating sound? (how long to sleep? how do you know how much sound to generate? and doesn't that generated sound interfere with the "real" sound?)