Asynch crash when e.Cancel set?

D

David Veeneman

Does anyone knmow why an asynchronous worker method would crash if the
e.Cancel method is set to true, but not otherwise?

I'm working on a demo app with an asynchronous call, using the .NET 2.0
BackgroundWorker component. The app works fine if I let the worker method
proceed to completion. But if I cancel the worker method, it crashes.

Specifically, if I set the DoWorkEventArgs.Cancel property to true, the
worker thread crashes at the point where the worker method returns control
to the caller. If I set the Cancel flag to false, the operation is
cancelled, but the RunWorkerCompletedEventArgs.Cancelled property is wrong.

My worker method is called by the BackgroundWorker_DoWork event handler,
which passes in a WidgetList, a reference to the background worker (which
DoWork cast from its sender argument), and the DoWork event arguments. Here
is the worker method code:

private WidgetList PopulateList(WidgetList sourceList, BackgroundWorker
backgroundWorker, DoWorkEventArgs e)
{
// Create deep copy (by serialization)
WidgetList resultList = sourceList.DeepCopy();

// Populate result list
for (int i = 0; i < 100; i++)
{
// Add new widget to the list
WidgetItem widget = new WidgetItem(i);
resultList.Add(widget);

// Pause to simulate slow process
Thread.Sleep(100);

// Check cancellation
if (backgroundWorker.CancellationPending)
{
// Set DoWork event args
e.Cancel = false;

// Return unmodified list
return sourceList;
}

// Report progress
backgroundWorker.ReportProgress(i);
}

// Set return value
return resultList;
}

And here is the exception I'm getting when the app stops:

System.Reflection.TargetInvocationException was unhandled
Message="Exception has been thrown by the target of an invocation."
Source="mscorlib"
StackTrace:
at System.RuntimeMethodHandle._InvokeMethodFast(Object target,
Object[] arguments, SignatureStruct& sig, MethodAttributes methodAttributes,
RuntimeTypeHandle typeOwner)
at System.RuntimeMethodHandle.InvokeMethodFast(Object target,
Object[] arguments, Signature sig, MethodAttributes methodAttributes,
RuntimeTypeHandle typeOwner)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj,
BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo
culture, Boolean skipVisibilityChecks)
at System.Delegate.DynamicInvokeImpl(Object[] args)
at
System.Windows.Forms.Control.InvokeMarshaledCallbackDo(ThreadMethodEntry
tme)
at System.Windows.Forms.Control.InvokeMarshaledCallbackHelper(Object
obj)
at System.Threading.ExecutionContext.runTryCode(Object userData)
at
System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode
code, CleanupCode backoutCode, Object userData)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext
executionContext, ContextCallback callback, Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext
executionContext, ContextCallback callback, Object state)
at
System.Windows.Forms.Control.InvokeMarshaledCallback(ThreadMethodEntry tme)
at System.Windows.Forms.Control.InvokeMarshaledCallbacks()
at System.Windows.Forms.Control.WndProc(Message& m)
at
System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message&
m)
at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd,
Int32 msg, IntPtr wparam, IntPtr lparam)
at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG&
msg)
at
System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32
dwComponentID, Int32 reason, Int32 pvLoopData)
at
System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32
reason, ApplicationContext context)
at
System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason,
ApplicationContext context)
at System.Windows.Forms.Application.Run(Form mainForm)
at BackgroundWorkerDemo.Program.Main() in C:\Documents and
Settings\David Veeneman\My Documents\Visual Studio
2005\Demos\BackgroundWorkerDemo\Program.cs:line 17
at System.AppDomain.nExecuteAssembly(Assembly assembly, String[]
args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence
assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext
executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()

Any ideas as to what's going on here? Thanks.
 
D

David Veeneman

I found my answer. In the DoWorkEventArgs, e.Result can't be set if e.Cancel
is set to true. In my worker method, I was setting e.Cancel to true, then
setting e.Cancel to my unmodified source list, as an easy way of providing a
rollback in a cancellation.

The error doesn't show up until .NET creates the RunWorkerCompletedEventArgs
for the RunWorkerCompleted event. When it tries to set the e.Result
property, an InvalidOperationException will be thrown, with the error
message "Operation has been cancelled". If you then try to read e.Result in
the RunWorkerCompleted event handler, the app blows up. The moral of the
story is to check for cancellation before reading e.Result in a
RunWorkerCompleted event handler.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top