0

Reading these BackgroundWorker vs. ThreadPool vs. Thread tips, I decided to go with BackgroundWorker.

I know how to create such a thread by dragging-and-dropping its component from the Toolbox into my form, but since I need multiple such threads (a finite number between 10-20), I am not sure what the correct way to approach this is:

  • Drag and drop 10-20 of them, creating placeholders for them in code, but only start those that need to run, depending on application needs (in different scenarios I could run as little as 1-2 our of those 10-20 threads).

or

I prefer the drag-and-drop approach but I am not experienced in BackgroundWorker and I am not sure what the tradeoffs could be.

Any tips from experienced BackgroundWorker programmers?

Community
  • 1
  • 1
ateiob
  • 9,016
  • 10
  • 44
  • 55
  • 4
    Did you consider Tasks too (.NET 4)? – Matthias Meid Oct 24 '12 at 16:28
  • @Mudu No. Are there advantages of Tasks over BackgroundWorkers? – ateiob Oct 24 '12 at 16:29
  • 2
    It would help to know what the workers will do. – Jim Counts Oct 24 '12 at 16:33
  • @ateiob They have different uses. A `BackgroundWorker` isn't just a way of starting a background thread. It's also a way of managing updates to the UI therad as progress occurs, or when the task is completed. That makes it a bit "heavier", but useful if you actually utilize those features. Tasks are more lightweight; they can do all of those things, but it doesn't assume you *usually* will. In your case you probably want one background worker to start a long running task, and then that task will create other `Task` objects to do work in parallel. – Servy Oct 24 '12 at 16:35
  • @JimCounts Communicate with websites and process the information retrieved. That data will then go into a database. The WinForm is expected to reflect that DB change accordingly. – ateiob Oct 24 '12 at 16:35
  • 1
    @ateiob Are each of them caused by different user actions, or are you pressing one button and then starting them all? – Servy Oct 24 '12 at 16:36
  • @Servy One button starting them all. Oh and I forgot to mention that those threads will actually be **polling** the websites (once every 1-10 minutes), so perhaps *timers* will do, but with timers I am not sure how well they "background", that's why I chose the BackgroundWorker route. – ateiob Oct 24 '12 at 16:40
  • 1
    @ateiob If you're polling then they should indeed be Timers, and you are correct to worry about whether or not they run in the background. There are several timers to choose from. If you use the Windows.Forms.Timer then the `Tick` event runs in the UI thread; you need to either use asynchronous IO methods, use the async keyword (if you have .NET 4.5, which would be the best option) or do something else to move to a background thread. Or you could just use any of the other timers, as their events won't be triggered in the UI thread. – Servy Oct 24 '12 at 16:43
  • @Servy I tried that `System.Timers.Timer` and was surprised that it allowed me to update the UI controls. That made me a little suspicious about this. Shouldn't it throw an exception if I try to access a UI control? – ateiob Oct 24 '12 at 16:49
  • 1
    @ateiob Well, if you set `CheckForIllegalCrossThreadCalls` to false then no, it won't *always* throw an exception, it just *might* throw an exception or not work in some subtle way. One easy way to check is to just sleep for like 5 seconds; if the form freezes you're in the UI thread, if not you aren't. If you're not (and you shouldn't be) then you'll need to be able to marshal back to the UI thread to update controls with the results, when ready. Use `Control.Invoke` to do that. – Servy Oct 24 '12 at 16:56
  • @Servy Thanks for that tip. I didn't know about `CheckForIllegalCrossThreadCalls` because it doesn't appear in VS's Properties. Odd. But this is for a different posting, dedicated to this (if there isn't one already). – ateiob Oct 24 '12 at 17:10
  • @ateiob For the record, you shouldn't ever set that to false. It's *good* that you get an exception whenever modifying the UI in a non-UI thread. Setting it to false means that it will only sometimes fail, making it hard to spot the bugs before the application is released. – Servy Oct 24 '12 at 17:13

1 Answers1

1

You can create an array that holds them. For each you add a handler. When done, go through the array to dispose them. For example (sorry, this is translated from VB code, I'm no expert at C# so please regard as pseudo code at worst):

//globally
List<BackgroundWorker> workers = new List<BackgroundWorker>();

//within a sub/function
int numberOfWorkersNeeded = 10;
for (i = 0; i < numberOfWorkersNeeded; i++) {
    BackgroundWorker bg = new BackgroundWorker();
    bg.DoWork += new DoWorkEventHandler(MyWorkHandler);
    bg.RunWorkerCompleted += new RunWorkerCompletedEventHandler(MyWorkFinishedHandler);
    workers.Add(bg);
}

To remove (they are re-usable, so this is for when exiting or when you don't need workers anymore):

for (i = 0; i < workers.Count; i++) {
    if (!bg.IsBusy) {
        //remove handlers
        workers(i).Dispose();
    }
}

Trade-offs are as @ateiop stated, you need to create (and remove) the event handlers manually.

For BackgroundWorker you have two main events, DoWork and RunWorkerCompleted. In addition if you want to report progress you need to enable reporting (bg.WorkerReportsProgress = true;) and add handler for that as well (ProgressChanged).

In any case, you also need to handle workers that hasn't finished.

  • +1 for an actual code sample to create BackgroundWorkers programmatically. This may as well be the accepted answer (unless something better comes along), but what I like about the drag-and-drop approach is that you can define/access all its event handlers with a double-click. Here, I am never sure if I missed anything? – ateiob Oct 24 '12 at 16:44
  • tried to cleanup the vb translation, did i overlook anything? –  Oct 24 '12 at 16:44
  • @ateiob Given your comments above, about the fact that this is actually going to be run periodically every X minutes, it will change the answer a fair amount. – Servy Oct 24 '12 at 16:45
  • 1
    @AbdiasSoftware Was wondering if you were going to change it from 1 indexed to 0 indexed `for` loops ;) - I also find it odd that you declare `i` outside of the `for` loops, it's...unusual. – Servy Oct 24 '12 at 16:46
  • 2
    Ok, give me a hard time. I did provide an example. I think it's good enough to get OP going, agree? :-) –  Oct 24 '12 at 16:49
  • @AbdiasSoftware But you're a VB programmer. I'm therefore obligated to give you a hard time. – Servy Oct 24 '12 at 16:53
  • @servy I've programmed for 30 years, I don't care –  Oct 24 '12 at 16:56
  • Accepting. Note: It's `RunWorkerCompletedEventHandler`, not `RunWorkerCompletedHandler` as you wrote. – ateiob Oct 24 '12 at 19:38