Discussion:
[Audiere-users] Re: Audiere crash with OutputStreamPtr -- race condition discovered?
Tim Conkling
2005-12-07 18:12:04 UTC
Permalink
In my test program that I've written to track down this audiere bug, I've
been tracking the calls to ref() and unref() on my OutputStream to see what
I could discover. The general flow of things goes something like this:

- The OutputStream is created from OpenSound, and I manually ref() the
OutputStream* that's returned
- ref (me)
... time passes, eventually my OutputStream needs to be stopped to make room
for a new sound. I call stop() and unref() on my OutputStream:
- ref (StopEventImpl)
- unref (me)
- ref (StopEventImpl)
- unref (StopEventImpl)
- unref (StopEventImpl)

So, from my main thread, I call ref once when the sound is created, and
unref once right after I call stop() on the OutputStream*. In another
(audiere) thread, a StopEventImpl object calls ref twice and unref twice.
_Most of the time_ this works; the refs and unrefs all match up.

Every once in a while I get a crash. In my test program, this happens fairly
early on in program execution because I'm playing sounds very quickly, and
therefore I'm stop()'ing previously-playing sounds quite often.

Two threads are manipulating this OutputStream's refcount after I stop() is
called -- the thread that the StopEvent is executing in, and my program's
thread, where unref() is called immediately after stop(). Am I wrong in
thinking that this is a race condition? Couldn't both threads decrement the
refcount before either has a chance to check if the decremented refcount ==
0 (presumably "if(--m_refCount == 0)" is not an atomic operation), and
therefore both try to "delete this;"?

I guess there are a few possible scenarios here:
- My understanding of the situation is incorrect -- there isn't a potential
race condition in RefPtr<>; the source of my problem lies elsewhere
- My understanding of the situation is correct -- there's a race condition,
but only because I'm using OutputStream incorrectly
- My understanding of the situation is correct -- there's a race condition,
and it needs to be fixed somehow.

Any thoughts?

Thanks,
Tim
I then reasign
outputStreamPtr to the value returned from audiere::OpenSound(). The
if(sounds_playing == max)
{
OutputStreamPtr outputStreamPtr = findOldestSound();
outputStreamPtr = NULL;
outputStreamPtr = audiere::OpenSound(...)
outputStreamPtr->play();
}
Whoops -- what I typed above is incorrect. I'm not creating a new
OutputStreamPtr (so there's not actually an extra ref()/unref()). In
fact, I never create new OutputStreamPtrs -- there's a single array of
them that I maintain. This would be more accurate pseudocode of what
if(sounds_playing == max)
{
OutputStreamPtr& outputStreamPtr = findOldestSound();
outputStreamPtr = NULL; // unref old OSP
outputStreamPtr = audiere::OpenSound(...); // ref new OSP
outputStreamPtr->play();
}
I just want to make it clear that I don't have any extra refs() and
unrefs() that I'm not noticing in my code (just to make sure, I
changed my array of OutputStreamPtr's to an array of OutputStream*'s,
and manually ref() after OpenSound(...) and unref() right before
setting the ptr to NULL.
Everything else I wrote in my previous email was correct :)
Thanks,
Tim
Loading...