The problem is very simple, yet I haven't found any specific article.
I want to be able to download a file async, wait until it completes, show a progress bar, but then continue from the point where I was in the main thread, and NOT from the filecompleted raised event. I need the file download to be async because I need to show a progress bar. And I'm forced to use .NET 2.0.
All the pages I found are solving this problem simply running the DownloadFileAsync as the last command, so there's nothing more to run... this way is simple, because the execution "continues" when the downloadfilecompleted triggers. All, all, all the samples I searched are working this way.
But what I need is to remain on the main thread, wait, let the downloadprogresschanged access the UI to update a progressbar, and then continue from there.
Something like this:
private ManualResetEvent myMREDown = new ManualResetEvent(false);
WebClient myClient = new WebClient();
myClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(myClient_DownloadProgressChanged);
myClient.DownloadFileCompleted += new AsyncCompletedEventHandler(myClient_DownloadFileCompleted);
myClient.DownloadFileAsync(SomeURL);
mre_DownloadingFile.WaitOne();
ContinueDoingSomethingElse(); // <-- I want to reach THIS point after download
void myClient_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
//update the progress bar
}
void myClient_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
mre_DownloadingFile.Set();
}
Now, my questions are:
A) Generally speaking, if I just run DownloadFileAsync, I understand the download happens in a separate thread, because if I write some more code after that, it will be run without waiting for the DownloadFileAsync to complete... however, if I WaitOne() from my main thread, that download thread seems to hung, because it doesn't shows any progress bar... So... it's on a separate thread from mine or not ???
B) If I wrap the entire download process into a method and then I use Start New Thread() to run it, and after that I use a ManualResetEvent Waitone(), the UI freezes the same...
C) Most of all... is there a wayout ???? (please providing code too, if possibile)
Ok I went deep on the problem and so I'll reply to myself, I hope this will help someone else with my same doubts.
Answers:
A) Generally speaking, if I just run DownloadFileAsync, I understand
the download happens in a separate thread, because if I write some
more code after that, it will be run without waiting for the
DownloadFileAsync to complete... however, if I WaitOne() from my main
thread, that download thread seems to hung, because it doesn't shows
any progress bar... So... it's on a separate thread from mine or not
???
The problem is: you can't wait on the main UI thread. That means that when you run the program, it normally runs on a thread that is the one that has access to the UI. So, no matter what you do and how, if you WaitOne() there, your UI will freeze. No wayout to this. Keep it as it is.
When you run the DownloadFileAsync it SPAWNS a new thread, but since from there you are trying to update a progress bar that is on the main thread, if that thread is waiting, it will not be able to do anything. So the problem is, again, you can't wait on the main thread.
B) If I wrap the entire download process into a method and then I use
Start New Thread() to run it, and after that I use a ManualResetEvent
Waitone(), the UI freezes the same...
The reason is the same of point A) - even if you start a new thread, but then you wait on the main thread UI, you'll not be able to go anywhere.
C) Most of all... is there a wayout ???? (please providing code too,
if possibile)
Yes, the solution is: think your program differently. Since you can't wait there, you need to recode everything so that you must be able to run the asyncdownload, abandon the program logic you were doing until then, and continue it elsewhere (from the DownloadFileCompleted event in my case). You could for example run everything on a new thread, update the progress bar using delegates (so they'll call UI updates from the right thread), and then from this new thread you'll be able even to Wait(), because this will put the waiting on a separate thread, that is not the main one.
In my case, I had a list of commands to execute... so I first created a Queue and added all commands there, then I created a method "RunNextCommand" that dequeues the Element and runs the command, and if one of the commands is "downloadafile", then I just run the asyncdownload, and run one more "RunNextCommand" from the DownloadFileCompleted event.
This way you don't use DoEvents() (that is always a very bad idea), your CPU doesn't runs 100%, and your code is beautiful and clean ;-)
Thank you to myself. I'm welcome. Bye.
Related
I feel that the answer to this is due to me having an incorrect concept of how threads work, but here goes.
private void button1_Click(object sender, EventArgs e)
{
this.TestMethodAsync(); // No await, i.e. fire and forget
// ** Some code here to perform long running calculation (1) **
}
private async Task TestMethodAsync()
{
// Some synchronous stuff
await Task.Delay(1000);
// ** Some code here to perform long running calculation (2) **
}
First of all, I would not "fire and forget" an asynchronous method like this (I would use Task.Run) but I've come across code that does, and I'm trying to understand what the effect is.
In a WinForms application, which uses a WindowsFormsSynchronizationContext, my understanding of async and await tells me that when I click button1, the method will start synchronously on the UI thread. It will call TestMethodAsync and run synchronously until it reaches the await. It will then capture the context, start the Task.Delay task, and yield control to the caller. Since we are not awaiting this call, button1_Click will continue on the UI thread and start performing calculation (1).
At some point, Task.Delay(1000) will complete. A continuation will then run the remainder of the TestMethodAsync method using the captured context, which in this case means that the continuation will be run on the UI thread. This will now start performing calculation (2).
We now have two separate sections of code wanting to run on the same thread (the UI thread) at the same time. My investigations into this seem to suggest that the thread switches back and forth between the two sections of code in order to perform them both.
QUESTION:
I'm confused about exactly what is going on here. How is it possible to resume on a thread that is already running other code? What forces the thread to switch between the two sections of code that want to run? In general, what happens when you attempt to resume on a thread that is already running some other code?
(I suppose this isn't any different to how my click event runs on the UI thread in the first place, in as much as I know it runs on the UI thread, and I know the UI thread is also doing other stuff, but I've not really thought about it like this before.)
This is the secret that you do not understand: I give you the Windows Message Loop
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
MSG msg;
BOOL bRet;
while(TRUE)
{
bRet = GetMessage(&msg, NULL, 0, 0);
if (bRet <= 0) break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
This is the actual "main" of your application; you just don't see it because it is hidden behind the scenes.
A simpler loop could not be imagined. It gets a message from the queue. If there are no more messages then the program must be done. If there was a message then it runs the standard message translations and dispatches the message, and then keeps on running.
How is it possible to resume on a thread that is already running other code?
It isn't. "Resuming on a thread that is running other code" is actually putting a message in the queue. That "other code" is being synchronously called by DispatchMessage. When it is done, it returns to the loop, the queue is polled, and the message indicates what code needs to be dispatched next. That then runs synchronously until it returns back to the loop.
What forces the thread to switch between the two sections of code that want to run?
Nothing. That doesn't happen.
In general, what happens when you attempt to resume on a thread that is already running some other code?
The message that describes what continuation needs to be run is queued up.
I suppose this isn't any different to how my click event runs on the UI thread in the first place, in as much as I know it runs on the UI thread, and I know the UI thread is also doing other stuff, but I've not really thought about it like this before.
Start thinking about it.
Click events are exactly the same. Your program is doing something; you click the mouse; the click hander does not interrupt the UI thread and start running new work on it. Rather, the message is queued up, and when your UI thread control returns to the message loop, the click is eventually processed; DispatchMessage causes Button1_OnClick to be invoked via some mechanism in Windows Forms. That's what WinForms is; a mechanism for translating Windows messages into calls to C# methods.
But you already knew that. You know that when an event-driven program does a long-running synchronous operation, that the UI freezes, but that click events are processed eventually. How did you think that happened? You must have understood at some level that they were being queued up for processing later, right?
Exercise: What does DoEvents do?
Exercise: Given what you now know: what could possibly go wrong if you call DoEvents in a loop to unblock your UI?
Exercise: How is await different from DoEvents in a GUI application?
How is it possible to resume on a thread that is already running other code?
It needs to be specifically designed to support it. There needs to be some framework in place that allows the thread to take in work and to then execute that work at some later point in time.
This is how your UI thread works. It has a queue, and whenever you schedule work to be done in the UI thread you add an item to the end of the queue. The UI thread then takes the first item from the queue, executes it, and then when it's done, goes on to the next item, and so on, until you end your application.
What forces the thread to switch between the two sections of code that want to run?
Nothing, because it doesn't do that. It runs one, then when it finishes, it runs the other.
In general, what happens when you attempt to resume on a thread that is already running some other code?
Either someone wrote some custom code to specifically do just that, in which case, it does whatever that code specifically told it to do, or else you can't.
I have a windows forms application
on which I need to use a for loop having a large number of Remote Calls around 2000 - 3000 calls,
and while executing the for loop, I loose my control on form and form controls, as it becomes a large process and some time it shows "Not Responding" but if I wait for a long it comes back again, I think I need to use some threading model for that, is there any idea, how can I proceed to solve the issue?
You need to perform the long running operation on a background thread.
There are several ways of doing this.
You can queue the method call for execution on a thread pool thread (See here):
ThreadPool.QueueUserWorkItem(new WaitCallback(YourMethod));
In .NET 4.0 you can use the TaskFactory:
Task.Factory.StartNew(() => YourMethod());
And in .NET 4.5 and later, you can (and should, rather than TaskFactory.StartNew()) use Task.Run():
Task.Run(() => YourMethod());
You could use a BackgroundWorker for more control over the method if you need things like progress updates or notification when it is finished. Drag the a BackgroundWorker control onto your form and attach your method to the dowork event. Then just start the worker when you want to run your method. You can of course create the BackgroundWorker manually from code, just remember that it needs disposing of when you are finished.
Create a totally new thread for your work to happen on. This is the most complex and isn't necessary unless you need really fine grained control over the thread. See the MSDN page on the Thread class if you want to learn about this.
Remember that with anything threaded, you cannot update the GUI, or change any GUI controls from a background thread. If you want to do anything on the GUI you have to use Invoke (and InvokeRequired) to trigger the method back on the GUI thread. See here.
private voidForm_Load(object sender, EventArgs e)
{
MethodInvoker mk = delegate
{
//your job
};
mk.BeginInvoke(callbackfunction, null);
}
private void callbackfunction(IAsyncResult res)
{
// it will be called when your job finishes.
}
use MethodInvoker is the easiest way.
Obviously, you need to use background threads. I suggest you read this free e-book.
I need to change the Label Content. but The code will sleep before execute it. So what's the different I use window execute the code or use control itself? like:
// Use Label execute
Label1.BeginInvoke(new Action(()=>{
System.Thread.Thread.Sleep(5000);
Label1.Content = "New Value";
});
// Use Window execute
MainWindow.BeginInvoke(new Action(()=>{
System.Thread.Thread.Sleep(5000);
Label1.Content = "New Value";
});
No matter I use Label or Window, it always stuck the UI when the Thread sleep. Why? Why it just don't freeze the label when we execute Label.BeginInvoke() , If Is there no any different, Why Microsoft not remove the Mothod for Control.Begininvoke()
Update1:
Sorry for the Sleep(5000), I just let you know there is a method will take a lot time for execute before change the Label Content.
Update2
So If there is no any different, Then no different with Control2.BeginInvoke() and Control3.BeginInvoke() ?
Then Why Microsoft just don't keep only the Window.Begininvoke()?
Update3
Why I can change the Control2.Content in Control3.BeginInvoke? If there is no limit Why All has that method? what for?
Update4
Maybe the Update2-3 is dummy qustion, sorry for that, what I mean is : If we can change the label1.content in windows.begininvoke(), why we still need label1.begininvoke()?
From the documentation of Control.BeginInvoke
Executes the specified delegate asynchronously on the thread that the control's underlying handle was created on.
The documentation of Thread.Sleep
Suspends the current thread for the specified amount of time.
Both the Window and the Label were created on the same thread (the UI thread). When you call Thread.Sleep() on that thread (using BeginInvoke) it does exactly what you would expect it to and causes the thread to get suspended (this thread is responsible for listening to windows messages and keeping the UI "responsive" which is why your application freezes)
I noticed that in one of your comments you wrote
#alykins, Because That mean there is some method will take alot time, and I don't let the main UI thread stuck in there.
The solution to this problem is not to call Sleep on the UI thread. You need to hand off the long running task to a separate worker thread and not do it on the UI thread. Consider reading up on the Task Parallel Library for one way to do this.
Answer to your latest update
If we can change the label1.content in windows.begininvoke(), why we still need label1.begininvoke()?
In the unlikely scenario that your Label and Window were created and owned by separate threads (and not the UI thread), you would use Label.BeginInvoke() to update the Label and Window.BeginInvoke() would not work`.
what is the problem in the code part below? Any ideas? I m sending command to my device through serial port. After each command the device will work for this command and then the other command comes for it and continues like this.
in Button Click event
{
function1();
Thread.Sleep(5000);
function2();
Thread.Sleep(5000);
function3();
}
I figured out if i erase second sleep and function3 from the code like below, it does both two function but if i want to continue like this way it does not do the third one.
in Button Click event
{
function1();
Thread.Sleep(5000);
function2();
}
works...
Thank you
You're blocking the UI thread. Don't do that. It means your UI can't update itself. Instead, set a System.Windows.Forms.Timer to fire in 5 seconds with the next function to call. Alternatively, do all of this in a different thread entirely (possibly using Sleep, possibly using another kind of timer to fire on a thread-pool thread) and use Control.Invoke/BeginInvoke to marshall back to the UI thread when you need to update the UI itself.
EDIT: Given your "answer", it seems that blocking the UI thread was only one of the problems - and getting the device to respond properly at all is a bigger problem. You shouldn't just rely on sleeping for a certain amount of time. You should detect when the device has completed the previous command. It's possible that it doesn't give any feedback, but that would be horrifically poor design. If at all possible, investigate how to read feedback from the device as to when it's finished (e.g. reading from the serial port!) and only start the next command when the previous one has finished. Depending on how you receive the feedback, you could use a blocking call on a non-UI thread, or use an asynchronous model to trigger things.
The BackgroundWorker might be a solution to solve the blocking of the UI.
Get rid of the Sleeps If the functions are creating their own threads, give them callback methods that trigger the next function after the first has finished.
As the code is presented there it is nothing wrong with it. It will:
Execute function 1
Sleep 5 seconds
Execute function 2
Sleep 5 seconds
Execute function 3
However since this is on a GUI event it will freeze the application while doing so. Consider spinning off the execution into a thread instead.
In .Net 4.0:
Task.Factory.StartNew(() => sendData());
In all .Net versions:
System.Threading.Thread myThread = new System.Threading.Thread(sendData);
myThread.IsBackground = true;
myThread.Start();
And then you have your sendData method:
private void sendData()
{
function1();
Thread.Sleep(5000);
function2();
Thread.Sleep(5000);
function3();
}
If you really need to do stuff in the GUI thread you can make it more responsive by regularly calling Application.DoEvents();, but this is not a good way of solving it.
Also remember that you can't access the GUI from other threads. See http://kristofverbiest.blogspot.com/2007/02/simple-pattern-to-invoke-gui-from.html for sample code on how to invoke the GUI thread from other threads.
Thank you guys. I solve it. The problem is i did not make thread sleep enough. 5000 ms do not enough for the second command.
I have a windows forms application
on which I need to use a for loop having a large number of Remote Calls around 2000 - 3000 calls,
and while executing the for loop, I loose my control on form and form controls, as it becomes a large process and some time it shows "Not Responding" but if I wait for a long it comes back again, I think I need to use some threading model for that, is there any idea, how can I proceed to solve the issue?
You need to perform the long running operation on a background thread.
There are several ways of doing this.
You can queue the method call for execution on a thread pool thread (See here):
ThreadPool.QueueUserWorkItem(new WaitCallback(YourMethod));
In .NET 4.0 you can use the TaskFactory:
Task.Factory.StartNew(() => YourMethod());
And in .NET 4.5 and later, you can (and should, rather than TaskFactory.StartNew()) use Task.Run():
Task.Run(() => YourMethod());
You could use a BackgroundWorker for more control over the method if you need things like progress updates or notification when it is finished. Drag the a BackgroundWorker control onto your form and attach your method to the dowork event. Then just start the worker when you want to run your method. You can of course create the BackgroundWorker manually from code, just remember that it needs disposing of when you are finished.
Create a totally new thread for your work to happen on. This is the most complex and isn't necessary unless you need really fine grained control over the thread. See the MSDN page on the Thread class if you want to learn about this.
Remember that with anything threaded, you cannot update the GUI, or change any GUI controls from a background thread. If you want to do anything on the GUI you have to use Invoke (and InvokeRequired) to trigger the method back on the GUI thread. See here.
private voidForm_Load(object sender, EventArgs e)
{
MethodInvoker mk = delegate
{
//your job
};
mk.BeginInvoke(callbackfunction, null);
}
private void callbackfunction(IAsyncResult res)
{
// it will be called when your job finishes.
}
use MethodInvoker is the easiest way.
Obviously, you need to use background threads. I suggest you read this free e-book.