Results 1 to 26 of 26

Thread: BackgroundMultiWorker

  1. #1

    Thread Starter
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    110,274

    BackgroundMultiWorker

    The BackgroundMultiWorker is modelled on the BackgroundWorker but provides support for multiple background operations. Each task is represented by a token, which can be any object at all. Just note that two value type objects with the same value will be recognised as the same token. As a result, using numbers or strings as tokens is not recommended if they may be duplicated. Instead, create a reference type object with a single property of the desired type.

    The members of the BackgroundMultiWorker closely resemble those of the BackgroundWorker class, except that most either require or provide a token to identify the current task. For instance, when calling RunWorkerAsync to start a new operation, you pass in a token to identify that operation. When the DoWork event is raised, that token is returned via the Token property of the DoWorkEventArgs object received by the event handler. This allows you to determine which task you're doing the work for.

    The CancellationPending and IsBusy properties of the BackgroundWorker have been translated to the IsCancellationPending and IsBusy methods of the BackgroundMultiWorker. Both are overloaded to allow you to determine the overall state or the state for a particular task, identified by a token.

    Finally, ReinstateCancelledOperation and ReinstateCancelledOperations methods have been added, allowing you to "uncancel" a cancelled task.

    I haven't actually tested the code yet but I thought I'd post it anyway. I'll get to testing it myself soon everyone is welcome to view the code and put it to use if they're happy to fix any issues that arise themselves.

    Note that the solution was created in VS 2010 targeting .NET 2.0. If you're using an earlier version of VS, you should be able to just create your own Class Library project and import the code files. In that case, you will need to reference System.Drawing.dll for the ToolboxBitmap attribute.

    UPDATES:

    1.0.0.1: Added DefaultEvent attribute and test application.
    Attached Files Attached Files

  2. #2
    New Member
    Join Date
    Mar 2011
    Posts
    1

    Re: BackgroundMultiWorker

    Hi
    Do you have some sample code to demonstrate how to use this submission?

    Thanks
    Allan

  3. #3

    Thread Starter
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    110,274

    Re: BackgroundMultiWorker

    Quote Originally Posted by allan@singaporerc.co View Post
    Hi
    Do you have some sample code to demonstrate how to use this submission?

    Thanks
    Allan
    If you know how to use a BackgroundWorker then you know how to use a BackgroundMultiWorker. If you don't know how to use a BackgroundWorker then there's plenty of information around on that topic, including my own thread in this very CodeBank. You can find that thread via the CodeBank link in my signature.

  4. #4

    Thread Starter
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    110,274

    Re: BackgroundMultiWorker

    I have updated the attachment in post #1. The BackgroundMultiWorker class itself remains unchanged except for the addition of the DefaultEvent attribute. This means that you can now double-click an instance in the designer to generate a handler for the DoWork event, just as you can with the BackgroundWorker class.

    The big news is that I've added a demo/test application. It lets you choose a number of tasks to run and then start that many tasks using the one BackgroundMultiWorker instance. It will display a row for each task in a grid and display the elapsed time as the tasks proceed. You can cancel individual tasks or all remaining tasks, receiving a prompt for each one. Finally, the progress rows are transferred to another grid that displays completed tasks, whether they were cancelled and, if not, the total elasped time.

  5. #5
    Fanatic Member coolcurrent4u's Avatar
    Join Date
    Apr 2008
    Location
    *****
    Posts
    993

    Re: BackgroundMultiWorker

    for the sake of those of us still using vb2008 & 2005, can you port your code to those enviroment?
    Programming is all about good logic. Spend more time here


    (Generate pronounceable password) (Generate random number c#) (Filter array with another array)

  6. #6

    Thread Starter
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    110,274

    Re: BackgroundMultiWorker

    Quote Originally Posted by coolcurrent4u View Post
    for the sake of those of us still using vb2008 & 2005, can you port your code to those enviroment?
    Just create a new project and import the code files. If there is VB 2010-specific code in there then you can just fix each error specifically or, if you don't know how, ask here.

  7. #7
    Banned
    Join Date
    Mar 2009
    Posts
    764

    Re: BackgroundMultiWorker

    i have no idea :
    1 what this program does ?
    2 what is a backround worker ?
    3 what is a token ?

  8. #8

    Thread Starter
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    110,274

    Re: BackgroundMultiWorker

    Quote Originally Posted by moti barski View Post
    i have no idea :
    1 what this program does ?
    2 what is a backround worker ?
    3 what is a token ?
    4 how to search the web ?

  9. #9
    Banned
    Join Date
    Mar 2009
    Posts
    764

    Re: BackgroundMultiWorker

    Quote Originally Posted by jmcilhinney View Post
    4 how to search the web ?
    according to the web token is the brown kid from southpark, but
    a token is a coin so...

    thanks john
    Last edited by moti barski; Mar 21st, 2011 at 12:00 PM.

  10. #10
    Fanatic Member coolcurrent4u's Avatar
    Join Date
    Apr 2008
    Location
    *****
    Posts
    993

    Re: BackgroundMultiWorker

    hello Jmc

    i have a class that download and extract data, and i assign that to the multiple background worker, i had to place a SyncLock on the part that downloads data, this is because the the module that downloads data, there are local variables to that sub, so i fear another worker might overwrite these variables before the previous worker finish using it.

    somthing lick this

    vb Code:
    1. sub dowork
    2. dim spider as new webSpider
    3. webspider.fetchdata()
    4. end sub
    now somewhere inside spider class in the download webpage module
    vb Code:
    1. SyncLock(url)
    2. siteHtml=GetWebsiteHtml(url)
    3. endSyncLock

    the problem is that each worker thread must wait for the previous one to finish which defeats the purpose of using multiple worker threads in the first place, i was hoping there is a work around for this
    Programming is all about good logic. Spend more time here


    (Generate pronounceable password) (Generate random number c#) (Filter array with another array)

  11. #11

    Thread Starter
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    110,274

    Re: BackgroundMultiWorker

    @coolcurrent4u:

    If there's a shared resource that each thread uses briefly and occasionally then that's OK, but if all threads are competing for a shared resource at all times then using multiple threads is pointless. It's hard to say for sure with so little information but it sounds like your class should be using an instance variable and then you should be creating one instance per thread. That way, each thread has its own variable and there's no competition.

  12. #12
    Hyperactive Member
    Join Date
    Mar 2013
    Location
    San Francisco, CA
    Posts
    487

    Re: BackgroundMultiWorker

    Hi John -

    I have a question about your BackgroundMultiWorker that I hope you can help me with.

    I downloaded your .zip file and ran the demo successfully. It worked with no errors. I would like to use it in another project. So, I added the Wunnell.Threading project to one of my existing VS2010 VB.Net projects, created a reference to the Wunnell.Threading dll and proceeded to create the controls in my project that you had in your demo (e.g., DataGridView, buttons, etc.).

    My question: When I the start my project and click it's "Start Theads" button, the I can watch the step-by-step execution of it through your worker (BackgroundMultiWorker). To make the debugging easier, I set the Thread count spinner to "1". The worker's DoWork event fires, but the ProgressChanged event never fires...and the the new row is never added to the DataGridView. When the ProcessCompleted event fires, an error is raised when the runningRowsByToken try's to retrieve the row from its Dictionary.

    I think your demo is great, and would love to use it in my project. I've been looking at this issue all day and have not been able to figure it out. Do you have any advice for how I can get it working? I would really appreciate your help. Thanks.

    Mark

  13. #13
    Hyperactive Member
    Join Date
    Mar 2013
    Location
    San Francisco, CA
    Posts
    487

    Re: BackgroundMultiWorker

    John -

    One additional question...is it possible to pass more than just the token (GUID) to the DoWork event parameter of the worker? My project has a large datatable and my goal is to break it into multiple sub-tables (e.g., each one having 20 rows from the larger datatable). I would like to start each worker and pass it one of these sub-tables along with its token parameter. Then the DoWork event would perform the processing of the sub-table.

    I have used the BackgroundWorker in other projects and know how to send multiple parameters with the RunWorkerAsync event. Can I also do this with the BackgroundMultiWorker?

    If not, then I would probably look at creating a collection that would contain key/value pairs of tokens and sub-tables. I would have to manage this collection (adding the key/value pair with each workers' RunWorkerAsync event and removing key/value pairs with each worker's ProcessCompleted event, etc.).

    Thanks again for any advice you can give me.

    Mark

  14. #14

    Thread Starter
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    110,274

    Re: BackgroundMultiWorker

    Quote Originally Posted by Mark@SF View Post
    Hi John -

    I have a question about your BackgroundMultiWorker that I hope you can help me with.

    I downloaded your .zip file and ran the demo successfully. It worked with no errors. I would like to use it in another project. So, I added the Wunnell.Threading project to one of my existing VS2010 VB.Net projects, created a reference to the Wunnell.Threading dll and proceeded to create the controls in my project that you had in your demo (e.g., DataGridView, buttons, etc.).

    My question: When I the start my project and click it's "Start Theads" button, the I can watch the step-by-step execution of it through your worker (BackgroundMultiWorker). To make the debugging easier, I set the Thread count spinner to "1". The worker's DoWork event fires, but the ProgressChanged event never fires...and the the new row is never added to the DataGridView. When the ProcessCompleted event fires, an error is raised when the runningRowsByToken try's to retrieve the row from its Dictionary.

    I think your demo is great, and would love to use it in my project. I've been looking at this issue all day and have not been able to figure it out. Do you have any advice for how I can get it working? I would really appreciate your help. Thanks.

    Mark
    Have you set the WorkerReportsProgress property of the BackgroundMultiWorker to True? Just like for the standard BackgroundWorker, that property is False by default. That's tripped me up a number of times with the BackgroundWorker so I could have set it to True by default but I wanted to mimic the BackgroundWorker as closely as possible.

    If that doesn't alleviate the issue of the exception being thrown when RunWorkerCompleted is raised, please provide specifics of the exception.

  15. #15

    Thread Starter
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    110,274

    Re: BackgroundMultiWorker

    Quote Originally Posted by Mark@SF View Post
    John -

    One additional question...is it possible to pass more than just the token (GUID) to the DoWork event parameter of the worker? My project has a large datatable and my goal is to break it into multiple sub-tables (e.g., each one having 20 rows from the larger datatable). I would like to start each worker and pass it one of these sub-tables along with its token parameter. Then the DoWork event would perform the processing of the sub-table.

    I have used the BackgroundWorker in other projects and know how to send multiple parameters with the RunWorkerAsync event. Can I also do this with the BackgroundMultiWorker?

    If not, then I would probably look at creating a collection that would contain key/value pairs of tokens and sub-tables. I would have to manage this collection (adding the key/value pair with each workers' RunWorkerAsync event and removing key/value pairs with each worker's ProcessCompleted event, etc.).

    Thanks again for any advice you can give me.

    Mark
    It works the same way as a regular BackgroundWorker but with the addition of the token. When you call RunWorkerAsync you can either pass no arguments or one object. That object can be of any type you like and can therefore be as complex as you like. It's completely up to the DoWork event handler to interpret and use that object.

    The same goes for the BackgroundMultiWorker. When you call RunWorkerAsync you can pass just the token or the token and one object. That object can be anything you like and therefore as complex as you like and it's completely up to the DoWork event handler to interpret and use it.

  16. #16
    Hyperactive Member
    Join Date
    Mar 2013
    Location
    San Francisco, CA
    Posts
    487

    Re: BackgroundMultiWorker

    Thank you so much for responding to my questions! I wasn't sure if you were still monitoring this thread since there haven't been any postings for more than a year.

    I understand your comments to my second question. I'll work on that tomorrow.

    As for my first question, I would like to provide some specifics. First off, there is no exception (error) when I click the start button. As I mentioned, I single-stepped through the code execution and saw that the ProcessChanged event simply never fires. I worked on this most of the day today and finally gave up trying to get it to work in my initial project. I began this project by creating a new VS2010 project in VB.Net. I added your demo Wunnell.Threading project as a second project to my solution, created a reference to the Wunnell.Threading.dll file, and then *created from scratch* a new form and each of the controls that you have in Form1 of your BackgroundMultiWorker Test project. So, after a lot of time convincing myself that I didn't know what I was doing, I gave up this approach and instead started a new project - but this time I added both your Wunnell.Threading project and your BackgroundMultiWorker Test project to my solution (it now only has those 2 projects). I created the Wunnell.Threading.dll reference. Everything compiled perfectly and your demo application worked in my new project. After I confirmed that the demo worked, then I went about modifying your Form1 and its code to work with my application. My summary...the first crack I took at creating a new project and trying to mimic your Form1 controls and code was not successful because something (or possible may things) weren't exactly duplicated. But I would still like to know what I did wrong (always on a "learning curve' and enjoy the journey). Any of my future projects that use the BackgroundMultiWorker would be nice to not have to go through the steps of adding the BackgroundMultiWorker Test project and then re-working the Form1 controls, code, etc. to fit my application.

    One last question: Why is the _ReSharper.Wunnell.Threading folder's included with the files in your demo .zip file? What is this folder and it's files purpose?

    John, I really appreciate that you have taken the time to respond to my questions and I've really gained a lot by using your BackgroundMultiWorker. If you'd like to see a screen shot of the application I've built with it, I'd be happy to e-mail it to you.

    All the best,

    Mark

  17. #17

    Thread Starter
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    110,274

    Re: BackgroundMultiWorker

    The only reason that I can think of that the ProgressChanged event wouldn't be raised is that the WorkerReportsProgress property was set to False. That property's entire reason for existing is to specify whether or not the ProgressChanged event is raised, so it's the obvious reason too. If you don't specifically remember setting that property to True then you probably didn't.
    Quote Originally Posted by Mark@SF View Post
    One last question: Why is the _ReSharper.Wunnell.Threading folder's included with the files in your demo .zip file? What is this folder and it's files purpose?
    ReSharper is a plugin for VS that provides extended Intellisense, refactoring and more. Those folders are created by ReSharper to remember project-specific settings. I usually delete those when I upload a demo but I forgot in this case. If you don't have ReSharper installed then they will simply be ignored.

  18. #18
    Hyperactive Member
    Join Date
    Jan 2009
    Posts
    429

    Re: BackgroundMultiWorker

    Its really great. I was just thinking if you can implement a function to pause it. Currently I am using a endless loop to pause a thread.
    Never Give UP! It is Mindset that brings you success!

  19. #19

    Thread Starter
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    110,274

    Re: BackgroundMultiWorker

    Quote Originally Posted by yogesh12 View Post
    Its really great. I was just thinking if you can implement a function to pause it. Currently I am using a endless loop to pause a thread.
    The simplest way to pause code is by calling Thread.Sleep. You don't want to do that on the UI thread though, because it will freeze the UI. The whole point of this class is to execute code on secondary threads though, so you can probably call Thread.Sleep with impunity in the DoWork event handler or any method called from it.

  20. #20
    Hyperactive Member
    Join Date
    Jan 2009
    Posts
    429

    Re: BackgroundMultiWorker

    Quote Originally Posted by jmcilhinney View Post
    The simplest way to pause code is by calling Thread.Sleep. You don't want to do that on the UI thread though, because it will freeze the UI. The whole point of this class is to execute code on secondary threads though, so you can probably call Thread.Sleep with impunity in the DoWork event handler or any method called from it.
    Currently What i have did is,

    1. Declaring a shared boolean variable on Main Form. When pause is clicked, i change value there.
    2. Adding a function to check if pause = true, if its true then starting a endless loop

    like this.

    While pause
    end while

    this is done in my worker class. so it doesnt hangs up UI. is this correct way?
    Never Give UP! It is Mindset that brings you success!

  21. #21

    Thread Starter
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    110,274

    Re: BackgroundMultiWorker

    Quote Originally Posted by yogesh12 View Post
    is this correct way?
    No it's not. That is a "busy wait" loop and is one of the worst constructs in programming. The desire is to do nothing but it's actually running your processor at 100% capacity! By calling Thread.Sleep you actually do tell the thread to do nothing. The thing is, you want to be able to continue again when the user says so so you can't actually do absolutely nothing. The solution is a compromise, but skewed heavily towards the "nothing" end rather than the "everything" end.
    Code:
    While pause
        Thread.Sleep(1000)
    End While
    Instead of constantly testing 'pause' like your original code, which will means thousands of times per second, That code tests 'pause' once per second. That means that there might be up to a second delay between the user clicking continue and the code actually continuing, but that's not really a big deal and will likely not even be noticed. If you want to reduce the potential delay then you can reduce the period of sleep. Even if the code tests twice, four times or even ten times per second, it's still going to be infinitely better than checking constantly.

  22. #22
    Hyperactive Member
    Join Date
    Jan 2009
    Posts
    429

    Re: BackgroundMultiWorker

    Quote Originally Posted by jmcilhinney View Post
    No it's not. That is a "busy wait" loop and is one of the worst constructs in programming. The desire is to do nothing but it's actually running your processor at 100% capacity! By calling Thread.Sleep you actually do tell the thread to do nothing. The thing is, you want to be able to continue again when the user says so so you can't actually do absolutely nothing. The solution is a compromise, but skewed heavily towards the "nothing" end rather than the "everything" end.
    Code:
    While pause
        Thread.Sleep(1000)
    End While
    Instead of constantly testing 'pause' like your original code, which will means thousands of times per second, That code tests 'pause' once per second. That means that there might be up to a second delay between the user clicking continue and the code actually continuing, but that's not really a big deal and will likely not even be noticed. If you want to reduce the potential delay then you can reduce the period of sleep. Even if the code tests twice, four times or even ten times per second, it's still going to be infinitely better than checking constantly.
    Yes your correct. I will change it.
    Never Give UP! It is Mindset that brings you success!

  23. #23
    Hyperactive Member
    Join Date
    Mar 2013
    Location
    San Francisco, CA
    Posts
    487

    Re: BackgroundMultiWorker

    jmcilhinney -

    I have implemented your BackgroundMultiWorker in an application. It works great, thanks to you.

    The application has a Tasks collection and each Task in the collection has a Status property ("Running", Cancelled", "Completed", or "Paused").

    I would like to pause a running background task. My form has a Pause button. The approach that I'm considering to pause a task is as follows:
    1. Click the Pause button which fires the button's Click event.
    2. The button's Click event sets the Task's Status to "Paused" if the Status is "Running", or to "Running" if the Status is "Paused" (essentially a toggle of the Status).

    In the BackgroundMultiWorker's DoWork event, I would handle pausing the Task by monitoring its Status. If the Status is "Paused", then I would enter a Do Loop with a System.Threading.Thread(1000) call to sleep for 1 second. Inside the loop I would test the Task's Status again and exit the loop if its Status is not "Paused". If the status is not "Paused", then the DoWork event proceeds a usual (looping through my database records and raising the BackgroundMultiWorker's ProgressChanged event with each loop).

    My question for you is how can I raise the BackgroundMultiWorker's DoWork event in the Pause button's Click event (and pass it the Sender object and the Wunnell.Threading.DoWorkEventArgs)? Or, if I'm not on the right track, then what would be a better approach?

    Can you help me with this? Would greatly appreciate your assistance.
    Last edited by Mark@SF; Jan 29th, 2014 at 06:15 PM.

  24. #24
    Hyperactive Member
    Join Date
    Mar 2013
    Location
    San Francisco, CA
    Posts
    487

    Re: BackgroundMultiWorker

    jmcilhinney -

    My question for you is how can I raise the BackgroundMultiWorker's DoWork event in the Pause button's Click event (and pass it the Sender object and the Wunnell.Threading.DoWorkEventArgs)?
    I have the pause/restart feature working by adding a task status property to the Tasks collection and using it to pause/restart the task. I am still be interested (as a learning point) in how to raise the BackgroundMultiWorker's events from outside of the BackgroundMultiWorker.

  25. #25

    Thread Starter
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    110,274

    Re: BackgroundMultiWorker

    Quote Originally Posted by Mark@SF View Post
    I am still be interested (as a learning point) in how to raise the BackgroundMultiWorker's events from outside of the BackgroundMultiWorker.
    You don't. You can't ever raise an object's events from outside. Only the object itself can raise its own event. The object might provide an interface to prompt it to do so, e.g. the Button.PerformClick method, but the raising of the event itself is still the responsibility of the object. The only way to raise a DoWork event on a BackgroundWorker is to call its RunWorkerAsync method. My BackgroundMultiWorker is modelled on the BackgroundWorker so the same rule applies.

  26. #26
    Hyperactive Member
    Join Date
    Mar 2013
    Location
    San Francisco, CA
    Posts
    487

    Re: BackgroundMultiWorker

    Thanks for your quick response, and your terrific BackgroundMultiWorker tool.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width