andriscs

Hi,

I have a method that calculates directory size recursively. With large directory structures it is quite slow so I decided to start it on a separate thread so I could use my form meanwhile. I read a lot about threading but something is not clear. Here is my code:

Code Snippet

delegate long MyDirSizeDelegate(DirectoryInfo di);
...
DirectoryInfo di=new DirectoryInfo(dir);
MyDirSizeDelegate mdsd = DirSize;
IAsyncResult res;
res = mdsd.BeginInvoke(di, null, null);
long size=0;
while (!res.IsCompleted)
{
Thread.Sleep(100);
}
size = mdsd.EndInvoke(res);



"We then call BeginInvoke. This begins execution while immediately returning control to the caller" as I read. I used Backgroundworker and it worked like dream when Thread.Sleep was called. How can I have the same here My form is frozen while the method is running. I could use BGW, but I decided to test this. I hope, I didn't do any lame thing.




Re: Windows Forms General Asynchronous calling question

andriscs

Hmm, I've read a little more about this. It says:
"Retrieving results is a simple operation; all that is required is a call to EndInvoke. However, there is an issue: if the async method has not completed, EndInvoke will block until it completes."
So what is the difference between this and a simple mehtod call Calling EndInvoke will block until it finishes. Calling a simple method - it also blocks the GUI from being refreshed. Then why should I use this I don't get it.
It has some code:
"
IAsyncResult ar = cpn.BeginInvoke( 672,
null,
null );

// Do some stuff
while( !ar.IsCompleted )
{
// Do some stuff
} "

Do some stuff What could I do with a dead form besides watching it crippled How can I make my form working while the method runs It seems BackgroundWorker is the only solution left.





Re: Windows Forms General Asynchronous calling question

inetscan

If you want to use the BeginInvoke delegate combination then you need to look into the second paramter of BeginInvoke which is an AsyncCallback delegate. The AsyncCallback holds which method to call once the method you BeginInvoke'd finishes which you can then retrieve the return value and do something with it.




Re: Windows Forms General Asynchronous calling question

andriscs

That's okay, that I can call a method after my slow method finished but my problem is that I cannot use (move, resize etc.) my form while the slow method is running and that's what I want. With backgroundworker it is possible, however I encountered an issue of it right now.





Re: Windows Forms General Asynchronous calling question

andriscs

Okay, it seems, I got it.
In the while loop Application.DoEvents() has to be called.





Re: Windows Forms General Asynchronous calling question

inetscan

Using a while loop to check if it is complete is the wrong approach and you are essentially killing the UI thread by doing so. Check out your CPU while that code is executing, it will very rapidly eat up available resources. Instead you should look into using a Callback method like I mentioned, then there would be no need for the while loop or the Application.DoEvents() call.



Re: Windows Forms General Asynchronous calling question

andriscs

Okay, but I don't understand, that why is better to call a method after the slow method is done. What am I supposed to do while the method is running





Re: Windows Forms General Asynchronous calling question

andriscs

You were right, the CPU usage was about 99%. Now I changed it and it seems almos working. I added a method that is called when the async method is done, but still have one question: how can I modify the GUI when that method is called I get a cross-thread warning if I try to modify GUI from the finishing method.

Code Snippet

DirectoryInfo di=new DirectoryInfo(dir);
MyDirSizeDelegate mdsd = new MyDirSizeDelegate(DirSize);
IAsyncResult res;
long size =0;
res = mdsd.BeginInvoke(di,new AsyncCallback(AfterReading), null);
...

private void AfterReading(IAsyncResult x)
{

label2.Text= mdsd.EndInvoke(x); //I get a cross-thread error here
}







Re: Windows Forms General Asynchronous calling question

Christopher Payne

Think of each of your threads as a different worker. Here's an example conversation to illustrate:

1. Polling Method

Bob: "Sue, go count the files in this folder."

Sue: "Ok, Bob, I'll go count them."

Bob: "Are you done yet "

Sue: "No"

Bob: "Are you done yet "

Sue: "No"

Bob: "Are you done yet "

Sue: "No"

Bob: "Are you done yet "

Sue: "No"

Bob: "Are you done yet "

Sue: "No"

Bob: "Are you done yet "

Sue: "Yes, there are 37 files."

2. Asynch method

Bob: "Sue, go count the files in this folder, and tell me when you're done."

Sue: "Ok, Bob, I'll go count them."

<some time later>

Sue: "Bob, there are 37 files in the folder."

In the polling method, what did Bob do while Sue was working Nothing...he just kept asking if she was done. That's the loop you set up with your Thread.Sleep call. The DoEvents isn't quite as bad, Bob gets to do small amounts of work in between asking Sue if she's done.

In the Asynch method, Bob was free to do whatever he wanted to while Sue was off doing the work. When Sue finished, she notified Bob...and that is what the delegate does that you pass to BeginInvoke...it notifies your program when the thread has finished.





Re: Windows Forms General Asynchronous calling question

andriscs

This explanation was very very useful, I appreciate it.
Meanwhile I figured out what to do. I had to call another async method to modify the GUI (this.BeginInvoke)
Thanks for all the hints!





Re: Windows Forms General Asynchronous calling question

sirjis

You don't have to call BeginInvoke to modify the GUI -- the Invoke method will also work, but it will block the worker thread until the call finishes.




Re: Windows Forms General Asynchronous calling question

andriscs

Yes, I know, it is a synchronous call. I will suffice as well. I guess, it is up to me which one I call but in this case async call is unnecessary. Am I correct





Re: Windows Forms General Asynchronous calling question

Jay A. Allen

andriscs, this was exactly why BackgroundWorker was created. BGW will fire progress and completion events that are marshaled onto the main UI thread, rather than executing from the worker thread. This will eliminate your cross-thread exceptions, and allow you to display progress notifications to the user. This article summarizes the situation nicely.






Re: Windows Forms General Asynchronous calling question

andriscs

andriscs wrote:

I could use BGW, but I decided to test this. I hope, I didn't do any lame thing.


I know, as I mentioned, but had to try this way.