views:

428

answers:

5

I used a Backgroudworker to do some work in order to do some time consuming tasks.

public void ConnectDataProvider()
    {
        bgw = new BackgroundWorker();
        bgw.DoWork += new DoWorkEventHandler(bgw_DoWork);
        bgw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgw_RunWorkerCompleted);

    }

Another method starts the background worker:

public void StartPolling()
    {
        bgw.RunWorkerAsync();
    }

Then I did the event handling:

void bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        // do it over again
        StartPolling();
    }    

void bgw_DoWork(object sender, DoWorkEventArgs e)
    {
        // do work
        WriteData();
    }

As you can see, I started the worker over on completion. Now this works for a single backgroundworker.

Now I want a collection, and each item should perform this task. However with the concept above it will just keep on running in the first worker started, as it starts the worker over. I'm thinking, maybe a Timer in combination could solve the situation to give the other worker threads way.

Is the BackgroundWorker still a good choice? Is it common to reuse the BackgroundWorker like I did?

EDIT 1: To clairify: The problem I'm facing is, that I need manage the collection each with their own BackgroundWorker. I was thinking about a timer, to set off request periodically from each item. This is where I'm stuck.

EDIT 2: See my own answer, I didn't solve this issue, but found that I can go along with timers to get what I wanted.

EDIT 3: To clarify (another try, I'm not good at that) what I wanted to achieve: I've got tracking objects, for gps tracking. I want to track a whole bunch of them, so one object per tracking device. They all need to be polled frequently. Ihad a BackgroundWorker set up for a single test object. I liked they way the Backgroundworker would tell me when it's done. But I couldn't get it working with all of the tracking objects.

Now every tracking object has its own timer. This timer spawns a new thread and does the time consuming work (which I named DoWrite). No BackgroundWorker needed, as I dispose the timer and then create a new timer. That's all it does.

A: 

When you have multiple time consuming tasks to be executed in the same time, I suggest you to use Thread Pool

http://msdn.microsoft.com/en-us/library/ms973903.aspx

Bogdan_Ch
I thought BackgroundWorker uses ThreadPool internally. That was one of the reasons I chose BackgroundWorker, so I don't have to take care of the maximum number of threads running.
rdoubleui
@rdoubleui- you are right it does use the threadpool internally.
RichardOD
sure, background worker uses Thread Pool but if you will want to create a collection of background workers (I understood your question in this way) you will get a collection of objects that manage collections of threads) so you are overdesining the application from my point of view.
Bogdan_Ch
and in the link that I posted, they tell something about timers. timers also use the Thread Pool, so in any case you will use it :)
Bogdan_Ch
Thank you Bogdan_Ch, I came up with the approach to only use timers, as you state. It seems to do the job. I'm just concerned of how "expensive" it is to use the timer only to throw it away and instantiate a new timer object after the task has been done.
rdoubleui
what timers do you use? I hope not Windows.Forms :) http://stackoverflow.com/questions/476598/system-windows-forms-timer-performance
Bogdan_Ch
No, I used System.Threading.Timer for my timers
rdoubleui
A: 

You can do exactly what you describe--just make sure that you pass the reference to the relevant background worker to StartPolling, thusly:

void bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    // do it over again
    StartPolling((BackgroundWorker)sender);
}

public void StartPolling(BackgroundWorker worker)
{
    worker.RunWorkerAsync();
}

Then obviously, you need to manage the collection of BackgroundWorker's accordingly.

Eric Smith
my approach was rather to give every item their own backgroundworker object. That management of the collection of the bg workers is exactly what I'm looking for.
rdoubleui
A: 

Since nobody did it so far, I'll throw in the timer approach. I tried to combine the two (BackgroundWorker and Timer), but that didn't make sense.

I wanted a mechanism to allow multiple instances to request data by thread. Also, I wanted some interval in between.

So after trying around, I figured I could get along with a Timer-approach only:

public void ConnectDataProvider()
    {
        timer = new Timer(new TimerCallback(tCallback), null, 0, Timeout.Infinite);            
    }

private void tCallback(object state)
    {
        timer.Dispose();
        // time consuming task
        WriteData();
        timer = new Timer(new TimerCallback(tCallback), null, 5000, Timeout.Infinite);
    }

That was what John Saunders suggested on a similar (but different) problem. It seems to do the job. The WriteData() has a synchronous HttpWebRequest, so it can handle a timeout.

My question now is: How expensive is the new instantiation of the timer object? By how expensive I mean: Are there better ways to achieve that?

Note: The asynchronous approach of the WebRequest won't work, I tried that. I have no clue so far, if that is a manner of the server.

rdoubleui
+1  A: 

Why don't you use the progresschanged event? You could use the userstate object for passing data.

In do work just pool the devices, and in process changed send the data to the UI thread.

Do it in a endless while and use cancel to stop that thread.

Regards.

Pablo Castilla
That's how I'd do it.
Allon Guralnek
+2  A: 

How many of these might there be? You should be careful of creating a 1:1 relationship between items in a collection and threads. Another coder might come along and expand this collection more than you planned.

For things like this I usually like to use just the one thread, and a queue - so the events just put the work that needs to be done in a ConcurrentQueue, and the thread starts if not running, and churns through the queued work until it's out of things to do, and dies. The next time more work comes in the event will check if the thread is running and start it.

It's cheaper because if there's a lot going on, you run just the one thread instead of stopping and starting a lot of them, or if there's very little going on, the one thread is almost never running.

Chris Moschini
This one makes sense to me. Thank You.
rdoubleui