0

Let's say I have a form with a piece of data that needs to be used in an await'ed method as such:

using (var riskForm = new RiskValidationForm(config))
{
   if (riskForm.OpenDialog() == DialogResult.Cancel)
      return;

   await Task.Run(() => MyMethod(riskForm.GetRiskData());
}

Is this dangerous? I'm afraid that the form might dispose, getting rid of what RiskData() returns before the awaited method is started. Hence I'd be calling RiskData() on something that is already disposed of. Is this possible?

Function signature of MyMethod:

private void MyMethod(RiskLimitsConfigurationCollection riskLimits)
  • No, the form object won't be disposed until the task completes. The *await* ensures this. You however do need to worry a bit about activating this code before the task is complete and what might happen when the form that contains this code is closed before the task is complete. – Hans Passant Apr 22 '20 at 15:48
  • @HansPassant What do you mean by "Activating" this code before it was complete? What I'm worried about is that the form that contains this RiskLimitConfigurationCollection is closed before the task is complete. It seems like you're saying two different things here. Can you clarify please? –  Apr 22 '20 at 17:51
  • I can't see how this code starts to run. Is it inside a Click event handler? Click the button again immediately after the dialog closes. Now you got MyMethod() running twice, concurrently. Rarely ends well, writing thread-safe code is hard to do. – Hans Passant Apr 22 '20 at 17:58
  • @HansPassant Shouldn't each of those clicks spin up its own form? I'm probably missing something though, been doing that all week :( – Lasse V. Karlsen Apr 22 '20 at 19:59

1 Answers1

0

No, it's not possible that the Form will be disposed before the completion of the Task. The await inside the using statement ensures that. But even if you removed the using/await combination (making the task essentially fire-and-forget) there would still be no problem. The garbage collector doesn't recycle objects that are still in use. The Task would hold a reference to a closure that would hold a reference to the RiskValidationForm, and Task objects are not recycled before their completion (unless the application is terminated).

You have two other reasons to worry though:

  1. You have to worry about the thread-safety of the MyMethod method. It may be called by multiple threads concurrently, unless there is UI code that prevents it from happening (for example by disabling the activation Button while the task is still running).
  2. You have to worry about the thread-affinity of the GetRiskData method. If this method accesses any method or property of any UI control of the RiskValidationForm form, you have committed a cross-thread violation because you have accessed a UI element from a thread other than the UI thread.
Theodor Zoulias
  • 34,835
  • 7
  • 69
  • 104