(Discussion) BackGroundWorker, Thread safety and Task pipelining/parallelization
Hi, I'm trying to have a BackGroundWorker do some stuff periodically and I'm having some doubts on how to correctly plan my software to make good use of the tools provided by VS and C#.
This is the scenario:
My software communicates with some hardware by USB.
Every X time, it measures n number of points, obtains data, processes it, adds it to chartAreas and stores it in a SQL DB.
What I do now is start a Timer to wait until X time has elapsed, then start with all the different (sequential) tasks. Start with point 1, have it's HW do what it has to do, meassure, collect the data, etc., move on to point 2, and so on until point n.
This, however, could also be done with a BGW (BackGroundWorker), to avoid having a Timer doing all that stuff. timer interval is 100 msec and what I need to do takes maybe minutes. Not good for the Timer...
Plus, the BGW can report progress. Now, some problems with that... BGW_DoWork() method cannot access the Windows Forms that my main GUI created, so I must tell BGW_ProgressChanged method what it has to update. I would have to provide info on chartArea, timeStamp and value for the (to be added) dataPoint.
BGW.ReportProgress() method can report progress % and an object with user data. This (I guess) would be how I can send data between the threads, but would require that I create a new encapsulating class that contains the targeted chartArea and the data I'm going to add.
I'm not particullary happy with that... I get this feeling I'm mixing stuff...?
Once I get one BGW to do all the stuff I need to, would it be safe to split all the work into n BGWs and have each one do the necessary work for each point? They would be accessing the USB port and recieving data, etc. If thread safety works, each BGW should get it's turn to send/recieve data and I would save a lot of time since I would have divided my processing time by n.
Some code that might help:
// Timer Tick. If the scheduled time to meassure has passed, start BGW
private void MainTimer_Tick(object sender, EventArgs e)
TimeSpan remainingTime = ScheduledToMeassure - DateTime.Now;
if (remainingTime.Ticks < 0) BackgroundWorker.RunWorkerAsync();
private void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
private void BackgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
// do things with e.UserState
private void MeassurePoints()
foreach (Point p in points)
BGW.ReportProgress(%, object) // object should include chartArea reference and dataPoint values (X, Y)
What would be the best way to define my classes/methods/objects so that interaction between them is as optimal, simple and safe as possible?
I'll be happy to fill in any other information/concepts you might need. Considering the nature of the post, I guess there will be a lot of that =)
Re: (Discussion) BackGroundWorker, Thread safety and Task pipelining/parallelization
Hi, yes, I am aware of that article on Thread-safe calls and have read it through. What you mention is the part specifically for BGW use. I could do that, but it would involve mayor changes I (think) should avoid.
The chartArea I'd be accessing is actually part of a class that will update it when it's data is.
I have a myOwnPointClass.Add(data) method, which then updates its private graphic objects according to the new data. So, resuming, I don't really have direct access to the object. I could of course rewrite the class to allow access, but I don't think it would be good programming. How can I check for invocation requirements from outside the class?
In any case, what MSDN says conflicts sometimes. If you take a look at the documentation on BackGroundWorker there is a big note saying:
"You must be careful not to manipulate any user-interface objects in your DoWork event handler. Instead, communicate to the user interface through the ProgressChanged and RunWorkerCompleted events."
From that same article, and related to the parallelization I mention in my first post, I think it would be easier to have multiple BGWs doing stuff, and having the e.Result variable set in each BGW_DoWork() Method, so that the BGW_RunWorkerCompleted() method can do what it has to do. This way I could fire all async workers at once and have them do all the work. This, however, would still require that I encapsulate a reference to the point being meassured, the values red and other info I need in a new class to be able to assign to e.Result, which I'm not particulary happy about.