I've recently tried to implement an asynchronous callback model, so that when developers consume my library, they don't need to worry about the following:
if(control.InvokeRequried) { // invoke }
That part of the code seems to be working quite nicely, but I discovered something a bit strange today, that I think I've diagnosed but would like to see what others with more experience think, and ways I might be able to resolve it.
The problem I've got, is it seems that my posts are very slow for some reason, and consequently they appear to get a little clogged up, and keep running after I've completed my work. A brief code example:
// called by user
WorkerEventHandler workerDelegate = new WorkerEventHandler(CalcAsync);
workerDelegate.BeginInvoke(p, asyncOp, null, null);
CalcAsync(P p, AsyncOperation asyncOp)
{
Calculate();
asyncOp.PostOperationCompleted(new AsyncCompletedEventArgs(null, false,
asyncOp.UserSuppliedState);
}
Calculate()
{
DoStuff() // updates the progress as it goes
this.UpdateStatus("Done"); // marks us as done
this.UpdateProgress(pId, 100); // increase progress to max
}
When stepping through I get repeated calls to an UpdateProgress being called from the posted events however, so it looks like they've been unable to keep up, and are still being posted. These are handled like so:
// initalized with
// onProgressUpdatedDelegate = new SendOrPostCallback(UpdateProgress);
private SendOrPostCallback onProgressUpdatedDelegate;
public void UpdateProgress(Guid pId, ProgressEventArgs e)
{
AsyncOperation asyncOp = GetAsyncOperation(pId);
if (asyncOp != null)
{
asyncOp.Post(this.onProgressUpdatedDelegate, e);
}
else
{
UpdateProgress(this, e);
}
}
private void UpdateProgress(object state)
{
ProgressEventArgs e = state as ProgressEventArgs;
UpdateProgress(this, e); // does the actual triggering of the EventHandler
}
If it's relevant these events are all writing to a console. But I seem to only see my progress go down on longer operations, which seems to be the same results I see through my WPF test app.
Does it suggest that the Post is just slow? I suppose what I'd really like is every time I call UpdateProgress via the Post I want to purge any existing posts within the queue if this is the case. But I'm not sure this is possible? If it is, is it possible to purge just for these events, as I don't want to then purge my UpdateStatus event accidentally...
Edit
Some of the missing methods if that makes it easier.
public void UpdateProgress(Guid pId, ProgressEventArgs e)
{
AsyncOperation asyncOp = GetAsyncOperation(pId);
if (asyncOp != null)
{
asyncOp.Post(this.onProgressUpdatedDelegate, e);
}
else
{
UpdateProgress(this, e);
}
}
private void UpdateProgress(object sender, ProgressEventArgs e)
{
ProgressChangedEventHandler handler;
lock (progressUpdateEventLock)
{
handler = progressUpdateEvent;
}
if (handler != null)
handler(sender, e);
}