views:

1245

answers:

3

Hello Guys, I am developing a application in C# which is getting data from Serial Port, Processing it and showing it to UI. The data is coming very fast between 5-50ms speed. Before I was not using any threads. and so application was relying on single App thread which was getting data from Serial Port, Processing data and showing it to UI. and It was loosing some data. Then I started implementing BackgroundWorker thread to remove some overhead on single thread and thinking of good performance. And Now I am getting "This BackgroundWorker is currently busy and cannot run multiple tasks concurrently" error. I think Thread is not able to cope up with the speed the data coming from Serial port. and So throwing error on executing "backgroundWorker1.RunWorkerAsync(data);". I need some suggestions what's the better approach to implement such kind of scenario?

Thanks in Advance -Chetan

A: 

The problem is that you're calling backgroundWorker1.RunWorkerAsync() before it's finished with its previous operation.

What you probably want to have is a single thread reading the serial port, buffering the data and notifying the main UI thread that data is available.

geofftnz
Thanks for quick response.I am using Single Background Worker thread to reading data from Serial port, Buffering data and notifying the UI. I think backgroundWorker1_RunWorkerCompleted event will notify that there is a valid output through if(e.Result != null) {} to UI thread correct me If I am wrong. - Chetan
Check out Mirozell's answer :)
geofftnz
A: 

Try adding this in, to make sure the background worker is only running one job at a time.

if(!backgroundWorker1.IsBusy)
    backgroundWorker1.RunWorkerAysnc();

You also have the ability to cancel the current job, here is a code sample

    private void WhereBackworkerStarts()
    {
        backgroundWorker.WorkerSupportsCancellation = true;

        if (backgroundWorker.IsBusy)
            backgroundWorker.CancelAsync();
        else
            backgroundWorker.RunWorkerAsync();
    }

    // Events
    static void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
    {
        for(int i = 0; i < int.MaxValue; i++)
        {
            if (backgroundWorker.CancellationPending)
            {
                e.Cancel = true;
                return;
            }

            // Do work here
        }
        e.Result = MyResult;
    }

    static void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        // Deal with results
    }
PostMan
I have already added this but in this case i am loosing some data when this thread is busy i mean data is not processed and not going to UI.
I am looking for the approach data should be continuously flowing.
Your best bet then is to use a threadpool, instead of a single backgroundWorker, as these *generally* are used for processing a nice amount of data behind the scenes, and periodically update the UI, while the UI is still responsive
PostMan
If I call CancelAsync() it will cancel my ongoing task. I don't want that. I want each task should be processed without loosing any data.
A nice tutorial on thread pools http://www.switchonthecode.com/tutorials/csharp-tutorial-using-the-threadpool
PostMan
Yes my mistake, I didn't see your comment before posting that
PostMan
see I am developing a software for showing the Live F1 race data on UI. I think this will help you to imagine what should be the speed the data is coming to seril port.I don't want any delays. and every data coming from Serial Port should processed.
I'd go with threadpools then, sounds like a complicated process, beyond the scope of a backgroundWorker. A link to an improved thread pool for C#, worth a look http://www.codeproject.com/KB/threads/smartthreadpool.aspx
PostMan
Ok Thanks buddy. I will look into this thread and mentioned Tutorial and try to figure it out. If any question, will come back to you techies.
+2  A: 

geofftnz is correct, and I'll expand a bit for you. You should only start the background worker once, and have it feed the data back to the GUI thread using ReportProgress. worker thread would look something like this.

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    BackgroundWorker worker = sender as BackGroundWorker;
    while(!e.CancellationPending)
    {
        ResultObject ro = new ResultObject();  // your own type here, obviously
        //Process and store some data in ro;
        worker.ReportProgress(0, ro);
        //Do not modify ro after reporting progress to avoid threading issues
    }
}

From the GUI, register to the ProgressChanged event, and only start the worker one time.

Mirozell
Thanks Mirozell, Here is the thing I am calling method which send my data to UI by checking value of ro Passed. but It's somehow not processing this function properly. and when I am debugging the function it's will not allow me to debug it properly and jumping back and forth. Don't know what's going on here.
Visual Studio will automatically jump you to any thread that hits a breakpoint. If you turn on 'Show threads in source' you'll get a little indicator of where other threads are. The easiest thing in your case is probably to remove/disable breakpoints in the worker while debugging the gui thread, and vice versa.
Mirozell
Guys I am able to resolve this. What i am doing is What ever the data I am getting from SerialPort I am adding that to Queue. and I am Dequeing the Queue using BackgroundWorker thread by checking it's busy status. and So No more getting any exception. Thanks to you all who spend there time in supporting me.