I think i have some problems with logic right now.
I have used a blocking collection to make thread safe calls to other PCs. In general it looks like this:
public class MyClass
{
private BlockingCollection<workUnit> workUnits = new BlockingCollection<workUnit>();
public void EnQueue(workUnit item)
{
workUnits.Add(item);
}
private void DeQueue()
{
while (!stopFlag)
{
workUnit item = workUnits.Take();
DoLongRunningDBStuff(workUnit);
}
}
}
Now I want to visualize this to a user.
A user should see that
- items are in Queue
- item processing has started
- result of processing (mainly passed/failed/exception)
And now I got some headache.
I was thinking to do the following:
Have a Grid to display the items to users.
- If item is Enqueued add it to workunits and additionally to a list bound to the datagrid
- If item is Dequeued (consumed) update the item in the list for the grid.
What makes the headache, is how to make this thread safe, and which parts are needed to be thread safe.
If I put something which takes time behind workUnit.Add I think it could be possible, that data gets mixed.
Would something like this be feasible?
- If item is Enqueued add it to workunits and an additional BlockingCollection for UI
- If item is Dequeued, make a tryget on 2. BlockingCollection and remove it there, update the status and attach it to second list again.
Would I need an additional lock aound 1 and 2? If so, wouldn’t it block completly the add if waiting for Take?
Is there an easy solution or approach to visualize, what is going on?
I will try do it this way:
in this example I would then make
workItem.SetState(...)fire an event that will update UI for the particular item. However, because the event is raised in a non-UI thread, it will be the handler of the event (the form displaying the grid I would assume) that would need to post the update into the context of the UI thread (e.g. If you are using WinForms you would call the Invoke method of the control displaying the data).In another (preferred) suggestion I would do the following (if you can use the TPL in .NET 4.0 and later):
And if you use .NET 4.5 you would be able to use the await feature that would automatically synchronise the continuation of the task in the context of the UI thread. E.g. in the on the caller’s side (assuming it is initiated on the UI thread) you would simply do the following:
In both examples you do not even need any locking, you simply need to have the updates posted to the correct context (and in the last example that is not even explicitly needed, the compiler takes care of it for you)