Click to See Complete Forum and Search --> : Best solution for problem needed


philkr
March 1st, 2006, 02:41 PM
I am working on a web radio application and using WSAAsyncSelect() to notify my dialog when new data is available. I then call the OnReceive() function of my web radio class. This function runs well when I only record the music using WriteFile(). Now I added a waveout class with a decode() function to enable live playback.
My problem is: The decode function takes so long that my dialog is completely blocked, doesn't react any longer to input and is not redrawn. I want to use multithreading to fix this.

The questions:

1) Where do I have to create the thread?
2) What should I call in the thread (I suppose the decode() function)?
3) How do I make everything threadsafe?

To answer question three you might have to know that the decode function receives a pointer to a buffer and its size as parameters. Currently the buffer is declared locally in OnReceive() function. I guess I have to change that when I use the thread, right?

MikeAThon
March 1st, 2006, 08:36 PM
Are you sure that multi-threading will help? It sounds like you have a CPU-bound process, where (for example) it takes more than a second to decode a second's worth of data. If your process is CPU-bound, than no amount of clever multi-threading would help.

If you think that multi-threading will help, then please also tell us how the decoder produces its output, and whether it can run in any thread (as opposed to being required to run in a particular thread)

Mike

PS: ...I then call the OnReceive() function of my web radio class...
I just want to clarify this statement. Is it your code that is actually making a call to OnReceive? Or are you relying on the inherent functionality of CAsyncSocket which automatically calls this function for you when new FD_READ notifications are received?

philkr
March 2nd, 2006, 04:45 AM
Are you sure that multi-threading will help? It sounds like you have a CPU-bound process, where (for example) it takes more than a second to decode a second's worth of data. If your process is CPU-bound, than no amount of clever multi-threading would help.
That is not the case. The audio is played completely right without any cracks or stutter and CPU usage is about 30 percent.
If you think that multi-threading will help, then please also tell us how the decoder produces its output, and whether it can run in any thread (as opposed to being required to run in a particular thread)
The decode() function uses mpglib decoder to decode the mp3 data and then sends it to wave output using waveOutWrite().
I'm afraid I cannot answer your other question.
I just want to clarify this statement. Is it your code that is actually making a call to OnReceive? Or are you relying on the inherent functionality of CAsyncSocket which automatically calls this function for you when new FD_READ notifications are received?
Let me clarify: I am not using CAsyncSocket class. I am using pure winsock functions using WSAAsyncSelect() to enable window message notification. When I get a message with event FD_READ in my window proc I call my OnReceive() function which is part of my self created shoutcast class. This function then calls recv() and sends the data to the decode() function.

philkr
March 2nd, 2006, 06:20 AM
Maybe I found the problem: Take a look at this part from my decode() function:
while(!m_nFreeBufferCount) Sleep(10);
Looks like this Sleep() blocks the dialog. But how can I use a thread in order to wait for a free buffer and at the same time save the buffer in a thread-safe manner.

MikeAThon
March 2nd, 2006, 04:06 PM
Maybe I found the problem: Take a look at this part from my decode() function:
while(!m_nFreeBufferCount) Sleep(10);
Looks like this Sleep() blocks the dialog. But how can I use a thread in order to wait for a free buffer and at the same time save the buffer in a thread-safe manner.
One common approach, which does not require threads, is to mimic your message loop inside the while loop, until a buffer becomes free:
while (!m_nFreeBufferCount)
{
MSG msg;
if ( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
This pumps exactly one message (if any are there) for each check for a free buffer.

Of course, this will not work if buffers do not become freed as a result of pumping messages. For example, if a buffer becomes free as a result of something you do in your OnReceive handler for FD_READ, then this might work.

Mike

philkr
March 3rd, 2006, 03:44 AM
Thanks for the reply!
In the meantime I have found another solution: I currently add the data to a kind of precache if no buffer is free and return from the function. That seems to work, though I have still some problems.
My audio gets sometimes corrupted or caught in a loop, but I guess that is some error in my metadata handling - maybe a part of the metadata is unintentionally also sent to the audio output and irritates the mp3 decoder.
I had also problems with randomly timed access violations. Then I guarded my decode() function call with a critical section and now it seems to work. But this error also left me wondering about the reason. I only can think of them a multithreading issue, but to be sure the following question has to be answered:

Is it possible that my window proc is called a second time before it has returned from a preceding call?
Because this would mean that my OnReceive() function could run multithreaded which is not intended and wanted avoided.

And a general question: What kind of errors do I get if my program is not threadsafe?

MikeAThon
March 3rd, 2006, 02:49 PM
...Is it possible that my window proc is called a second time before it has returned from a preceding call?
It's not only possible, but in fact it's very common. The most common example is where your program displays a modal dialog, such as MessageBox, from within some function. In this case, even though you have not yet returned from the function, messages are continuously pumped through your winproc, such as the WM_PAINT message which continues to draw your app's view.

Basically, anytime you call SendMessage or somehow pump messages from within your winproc, your winproc will get called again before it has returned from inside a first call.

Because this would mean that my OnReceive() function could run multithreaded which is not intended and wanted avoided.
It's not the same as multi-threaded; it's more like re-entrancy.

Mike