Click here to Skip to main content
15,867,704 members
Please Sign up or sign in to vote.
5.00/5 (1 vote)
Hi guys, I'm trying to wrap my mind around this asynchronous and background worker stuff ...
As a playground, i have a WPF application that searches for prime numbers.

Basics are easy. Create bgw (my short for BackGroundWorker), create DoWork, RunWorkerCompleted, ProgressChanged delegates. Once button clicked, run it async. once work is finished, update the GUI. Everybody happy. Here's the main code:
C#
private void btn_no_opt_go_Click(object sender, RoutedEventArgs e)
       {
           try {
               // Setting buttons states, showing progress bar, and setting the results label
               ...
               // Running our bgw worker.
               bgw.RunWorkerAsync(int.Parse(time_to_run.Text));
           } catch { ... }
       }

       // This does the work in an asynchronous way, calling the PrimeFinder class to do the heavy lifting.
       private void bgw_DoWork(object sender, DoWorkEventArgs e)
       {
           BackgroundWorker bgw = sender as BackgroundWorker;
           int arg = (int)e.Argument;

           // Start the time-consuming operation.
           PrimeFinder pf = new PrimeFinder(arg);
           e.Result = pf.No_Optimization(bgw);

           // Cancel code ....
       }

       // When method finishes, this runs
       private void bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
       {
           // cancel / error / else + button initialization
       }

       /// Method is called every time bgw.ReportProgress is called which triggers ProgressChanged event.
       private void bgw_ProgressChanged(bject sender, System.ComponentModel.ProgressChangedEventArgs e)
       {
           prgs_no_opt.Value = e.ProgressPercentage;
       }

       // Cancel the operation (only selectable when it's running)
       private void btn_no_opt_cancel_Click(object sender, RoutedEventArgs e) {...}

There's also a class called Prime Finder which has:
C#
// gets bgw so can call back with progress 
public PrimesResults No_Optimization(BackgroundWorker bgw)
{ 
   // hunt for primes, return an object when done
   ... 
}


The GUI looks something like this:
No Optimization: [ progress bar ] [Go button] [Cancel button]
Results label: [holds the result / cancel / error code]


This works nicely, and all are happy.

Now i want to improve and add another method that does things better. So, i'm adding to the GUI which now looks like:
XML
No Optimization: [ progress bar ] [Go button] [Cancel button]
Results label: [holds the result / cancel / error code]

Some Optimization: [ progress bar ] [Go button] [Cancel button]
Results label: [holds the result / cancel / error code]


So, i copy all my buttons and labels, paste them, rename them around so they make sense, and then i copy paste most of the above code. instead of bgw i have bgw_second, with listeners for bgw_second_DoWork instead of bgw_DoWork, and so on.

This seems silly, redundant, prone to mistakes, wasteful, and so on.
How could I have different buttons (each button has a matching "cancel" button), call and listen to different methods without copy pasting the above things?
Notice that different buttons call different bgw, which call another class with that bgw so they can report progress to the correct progress bar, and cancel the correct thread

Another question is: if I use 1 bgw, and call it with different parameters so it calls different methods, will it run on 1 thread, or will it spawn as many threads as needed (which is the case if i create 2 or more different bgw and each button calls one of them).
Having a multiple core CPU, hitting the Go button on the first method, will max one core while the process is working (makes sense, lots of calculations).
Hitting the first and then the second Go buttons, will max out 2 cores. Makes sense, since i'll take it them system spans 2 bgw, each gets his core, and they chunk away happily (or the equivalent to a core on different ones. looking at the task manager, i don't see one core being fully loaded, but i see the load is evenly shared (give or take)

So the question is if i use 1 bgw, and give him as an argument (from the button clicked) the method to call, will clicking those 2 buttons result in 2 threads being used (as it happens now), or will only 1 thread be used, sharing the time between the 2 calls.

I wanted to attach the project, but cant find an upload option.

Cheers :)
Posted
Updated 28-Dec-12 13:30pm
v2
Comments
Sergey Alexandrovich Kryukov 28-Dec-12 14:29pm    
First of all, why are you preoccupied with the idea of BackgroundWorker only? There are two more ways to get a thread. This way, you start not from the beginning.
You consideration about copy-paste are not clear. You first describe an obviously bad developer's behavior, and then asking how to avoid it. This is generally a wrong approach to the problem.
—SA
_Noctis_ 28-Dec-12 19:11pm    
Was looking into multithreaded, and this seemed like a simpler way than running threads and managing them, and this is what suggestions about keeping GUI active involved. I'll add some code and improve question :)
Sergey Alexandrovich Kryukov 28-Dec-12 19:28pm    
Nothing is simpler in all cases. It depends.
—SA

1 solution

Perhaps, first thing you need to understand is that the methods are completely agnostic to the thread they are executed in. Any thread can call any methods, and any method can be called in any thread. To really understand it, you should understand how all this call-and-return model really words. It's based on the stack, and each thread has its own stack, as well as other elements of the context.

First question remains unclear to me. The answer is yes, but the idea to use copy-paste in development of the project never even visit my head, so I simply don't see what's the problem. If you had to copy something, them this "something" had a lot in common. If it had anything in common at all, this common part should be abstracted out and used in two or more cases. Maybe, my first paragraph will explain to you, that there is no a hassle here. Also, please see my comments to the question. Anyway, "Don't Repeat Yourself" (DRY) is one of the first principles: http://en.wikipedia.org/wiki/Don%27t_repeat_yourself[^].

As to the second question: no, no threads are created without your explicit code which creates a thread or takes it from the thread pool. I don't even know how you came to this question. Probably, you are missing something very basic, but I cannot understand what.

—SA
 
Share this answer
 
Comments
Espen Harlinn 29-Dec-12 9:52am    
Good points :-D
Sergey Alexandrovich Kryukov 29-Dec-12 20:08pm    
Thank you, Espen.
—SA

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900