|
dev
newsgroups
|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
Threading: ThreadStart vs BeginXXX/EndXXXfor a lengthy download over HTTP. I soon arrived at the question: What is the best way to start a worker thread and why? As I see it, the framework gives us the ThreadStart delegate to do this, and also the BeginXXX/EndXXX model for asynchronous operations. The ThreadStart delegate usage is quite simple to understand. I've come to understand the other model, and now my refined question is: What benefits of going with the other model? I wrote some pseudocode below to illustrate the two different approaches to the same problem, and I can't see why the heck one would choose the latter. Thanks for any feedback! ------------------ ThreadStart approach ------------------ private void MainMethod() { Thread thread = new Thread(new ThreadStart(this.DownloadFile)); thread.Start(); thread.Join(); MessageBox.Show("I'm done.") return; } private void DownloadFile() { // Do some work // Update progressbar // Do more work // Update progressbar } -------------------------- Asynchronous method approach -------------------------- private void MainMethod() { IAsyncResult result = BeginDownloadFile(new AsyncCallback(EndDownloadFile)); result.WaitHandle.WaitOne(); MessageBox.Show("I'm done.") return; } private IAsyncResult BeginDownloadFile(AsyncCallBack callback) { // Set up my own worker thread, point it to DownloadFile using ThreadStart // Somehow register the callback method to a Thread complete event (????) // Start my thread // Package up my homerolled MyAsyncResult object and return it } private void DownloadFile() { // Do some work // Update progressbar // Do more work // Update progressbar } private void EndDownloadFile(IAsyncResult result) { ... } public class MyAsyncResult : IAsyncResult { ... } AMI <n*@reply.com> wrote:
> I started with a fairly simple task: Displaying a progressbar on a WinForm BeginXXX/EndXXX typically *don't* start an extra thread - they use the > for a lengthy download over HTTP. I soon arrived at the question: What is > the best way to start a worker thread and why? > > As I see it, the framework gives us the ThreadStart delegate to do this, and > also the BeginXXX/EndXXX model for asynchronous operations. The ThreadStart > delegate usage is quite simple to understand. I've come to understand the > other model, and now my refined question is: What benefits of going with > the other model? > > I wrote some pseudocode below to illustrate the two different approaches to > the same problem, and I can't see why the heck one would choose the latter. > Thanks for any feedback! ThreadPool instead. Of course you *could* start an extra thread, but if so you should warn people about this behaviour. You could use a custom thread pool as well, instead of the system thread pool. As for which is better, it really depends on how your class is going to be used. Note that start a new thread and then joining it immediately is almost always entirely pointless. -- Jon Skeet - <sk***@pobox.com> http://www.pobox.com/~skeet If replying to the group, please do not mail me too > BeginXXX/EndXXX typically *don't* start an extra thread - they use the Interesting, I didn't know that. Be that as it may, if I was able to mimic> ThreadPool instead. Of course you *could* start an extra thread, but if > so you should warn people about this behaviour. You could use a custom > thread pool as well, instead of the system thread pool. the ThreadPool behavior of BeginXXX/EndXXX, what then is the difference when compared to ThreadStart? I'm still trying to understand why there are two different models for asynchronous operations, and what the significance of the difference is. Given the relative complexity of BeginXXX/EndXXX, is it more a matter of form practiced by authors of class libraries rather than application developers? This too seems odd, since every method has the ability to be executed asynchronously via the ThreadStart approach. >Note that start a new thread and then joining it immediately One benefit of it would be that the main thread would be available to update> is almost always entirely pointless. the progress bar, right? Or does Thread.Join() block so that _nothing_ happens on that thread? Show quoteHide quote "Jon Skeet [C# MVP]" <sk***@pobox.com> wrote in message news:MPG.1c04006d63a4221498b8e7@msnews.microsoft.com... > AMI <n*@reply.com> wrote: > > I started with a fairly simple task: Displaying a progressbar on a WinForm > > for a lengthy download over HTTP. I soon arrived at the question: What is > > the best way to start a worker thread and why? > > > > As I see it, the framework gives us the ThreadStart delegate to do this, and > > also the BeginXXX/EndXXX model for asynchronous operations. The ThreadStart > > delegate usage is quite simple to understand. I've come to understand the > > other model, and now my refined question is: What benefits of going with > > the other model? > > > > I wrote some pseudocode below to illustrate the two different approaches to > > the same problem, and I can't see why the heck one would choose the latter. > > Thanks for any feedback! > > BeginXXX/EndXXX typically *don't* start an extra thread - they use the > ThreadPool instead. Of course you *could* start an extra thread, but if > so you should warn people about this behaviour. You could use a custom > thread pool as well, instead of the system thread pool. > > As for which is better, it really depends on how your class is going to > be used. Note that start a new thread and then joining it immediately > is almost always entirely pointless. > > -- > Jon Skeet - <sk***@pobox.com> > http://www.pobox.com/~skeet > If replying to the group, please do not mail me too AMI <n*@reply.com> wrote:
> > BeginXXX/EndXXX typically *don't* start an extra thread - they use the BeginXXX/EndXXX is usually (IME) used for IO operations which don't > > ThreadPool instead. Of course you *could* start an extra thread, but if > > so you should warn people about this behaviour. You could use a custom > > thread pool as well, instead of the system thread pool. > > Interesting, I didn't know that. Be that as it may, if I was able to mimic > the ThreadPool behavior of BeginXXX/EndXXX, what then is the difference when > compared to ThreadStart? I'm still trying to understand why there are two > different models for asynchronous operations, and what the significance of > the difference is. actually require a thread to be doing anything until something external happens. Sometimes it's more appropriate to use that model - other times you want to start a whole other thread. > Given the relative complexity of BeginXXX/EndXXX, is it more a matter of Yes, it's fairly rare to implement BeginXXX/EndXXX yourself. Don't > form practiced by authors of class libraries rather than application > developers? This too seems odd, since every method has the ability to be > executed asynchronously via the ThreadStart approach. forget that you can always use BeginInvoke/EndInvoke on arbitrary delegates, if you want. > >Note that start a new thread and then joining it immediately The latter - almost.> > is almost always entirely pointless. > > One benefit of it would be that the main thread would be available to update > the progress bar, right? Or does Thread.Join() block so that _nothing_ > happens on that thread? See http://blogs.msdn.com/cbrumme/archive/2003/04/17/51361.aspx It's all a bit difficult, but it's pretty nasty to rely on any pumping being done during Thread.Join. Treat it as a thoroughly blocking method. -- Jon Skeet - <sk***@pobox.com> http://www.pobox.com/~skeet If replying to the group, please do not mail me too Makes sense, but then I seem to be back at a simple WinForms question, which
is: What is the correct threading technique for invoking DoLengthyOperation() in response to a button click (and not wanting my form to freeze up, of course)? Show quoteHide quote "Jon Skeet [C# MVP]" <sk***@pobox.com> wrote in message news:MPG.1c04673c55464d9898b8eb@msnews.microsoft.com... > AMI <n*@reply.com> wrote: > > > BeginXXX/EndXXX typically *don't* start an extra thread - they use the > > > ThreadPool instead. Of course you *could* start an extra thread, but if > > > so you should warn people about this behaviour. You could use a custom > > > thread pool as well, instead of the system thread pool. > > > > Interesting, I didn't know that. Be that as it may, if I was able to mimic > > the ThreadPool behavior of BeginXXX/EndXXX, what then is the difference when > > compared to ThreadStart? I'm still trying to understand why there are two > > different models for asynchronous operations, and what the significance of > > the difference is. > > BeginXXX/EndXXX is usually (IME) used for IO operations which don't > actually require a thread to be doing anything until something external > happens. > > Sometimes it's more appropriate to use that model - other times you > want to start a whole other thread. > > > Given the relative complexity of BeginXXX/EndXXX, is it more a matter of > > form practiced by authors of class libraries rather than application > > developers? This too seems odd, since every method has the ability to be > > executed asynchronously via the ThreadStart approach. > > Yes, it's fairly rare to implement BeginXXX/EndXXX yourself. Don't > forget that you can always use BeginInvoke/EndInvoke on arbitrary > delegates, if you want. > > > >Note that start a new thread and then joining it immediately > > > is almost always entirely pointless. > > > > One benefit of it would be that the main thread would be available to update > > the progress bar, right? Or does Thread.Join() block so that _nothing_ > > happens on that thread? > > The latter - almost. > > See http://blogs.msdn.com/cbrumme/archive/2003/04/17/51361.aspx > > It's all a bit difficult, but it's pretty nasty to rely on any pumping > being done during Thread.Join. Treat it as a thoroughly blocking > method. > > -- > Jon Skeet - <sk***@pobox.com> > http://www.pobox.com/~skeet > If replying to the group, please do not mail me too AMI <n*@reply.com> wrote:
> Makes sense, but then I seem to be back at a simple WinForms question, which Start a new thread, and get that to call back into the form (using > is: > > What is the correct threading technique for invoking DoLengthyOperation() in > response to a button click (and not wanting my form to freeze up, of > course)? Invoke or BeginInvoke) when it's finished. -- Jon Skeet - <sk***@pobox.com> http://www.pobox.com/~skeet If replying to the group, please do not mail me too "AMI" <n*@reply.com> wrote in message news:Sukmd.92656$HA.63967@attbi_s01... ....>I started with a fairly simple task: Displaying a progressbar on a WinForm > for a lengthy download over HTTP. I soon arrived at the question: What > is > the best way to start a worker thread and why? There's a better question, and perhaps you already know the answer: .... > private void DownloadFile() Perhaps you know that you can't directly update the progress bar from > { > // Do some work > // Update progressbar > // Do more work > // Update progressbar > } another thread? In fact, you can't directly touch any part of the UI from another thread. Instead, you need to use Control.Invoke to marshall all of your UI work to the UI thread: private void UpdateProgressBar(ProgressBar bar, int progressValue) { bar.Value = progressValue; } private delegate void ProgressBarHandler(ProgressBar bar, int progressValue); private void DownLoadFile() { // Do some work // Update progressbar progressBar.Invoke(new ProgressBarHandler(UpdateProgressBar), new object[]{progressValue}); // Do more work // Update progressbar progressBar.Invoke(new ProgressBarHandler(UpdateProgressBar), new object[]{progressValue}); } of course, you can get fancy and hide all the Invoking inside of UpdateProgressBar: private void UpdateProgressBar(ProgressBar bar, int progressValue) { if (bar.InvokeRequired) { bar.Invoke(new ProgressBarHandler(UpdateProgressBar), new object[]{progressValue}); } else { bar.Value = progressValue; } } You probably knew this, but other readers might not have known... John Saunders P.S. I learned the hard way that this rule also applies to modifying objects which might raise events to the UI. I once had an application in which the main form displayed a DataGrid. The DataGrid was bound to a DataSet. The DataSet was being updated in a background thread. Bad Idea, as the DataGrid had created a DataView against the DataSet, and was listening to the ListChanged event of that DataView. My innocent addition of a row raised ListChanged - directly from my background thread to the DataGrid. Not a pretty sight.
Other interesting topics
Get the parent assembly
Convert a String into a Stream Bizarre Exception null value .Net Application crash No exception Thrown Re: File.Delete GDI and Image displays Isn't this possible in C#??? Server Freeze .NET 2.0 Beta 1 Error debugging web project. Re: looking for Book or online documentation on DotNet Framework Class Library |
|||||||||||||||||||||||