Throw Exception Object and Multithreaded Application

I have an application that starts System.Threading.Timer, then this timer every 5 seconds reads some information from the associated database and updates the GUI in the main form of the application;

Since System.Threading.Timer creates another thread for the Tick event, I need to use Object.Invoke to update the user interface in the main form of the application with this code:

this.Invoke((MethodInvoker)delegate()
  {
       label1.Text = "Example";
  });

The application works very well, but sometimes when the user closes the main form and closes the application, if the second timer_tick event stream updates the user interface in the main thread, the user gets an ObjectDisposedException.

How can I do to stop and close the streaming timer before closing the main form and avoid the exception of the object located on the side of the object?

+5
source share
3 answers

System.Timers.Timer is a terrible class. There is no good way to stop it reliably, there is always a race, and you cannot avoid it. The problem is that its Elapsed event gets from threadpool thread. You cannot predict when this thread will really start working. When you call the Stop () method, this thread may already be added to the thread pool, but it still does not work. It depends on both the Windows thread scheduler and the thread scheduler.

, . threadpool 125 . , , . 2 .

. System.Threading.Timer , . System.Windows.Forms.Timer, .

WF , Control.Invoke(). , . WF. โ€‹โ€‹

+3

,

  • . .
  • . .
  • , , . ,
  • Invoke.

, , , . , . , Invoke

static void Invoke(ISynchronizedInvoke invoke, MethodInvoker del) {
  try {
    invoke.Invoke(del,null);
  } catch ( ObjectDisposedException ) {
    // Ignore.  Control is disposed cannot update the UI.
  }
}

, , . , , , . , , :)

โ„– 2, . WinForms , .

static void InvokeControlUpdate(Control control, MethodInvoker del) {
  MethodInvoker wrapper = () => {
    if ( !control.IsDisposed ) {
      del();
    }
  };
  try {
    control.Invoke(wrapper,null);
  } catch ( ObjectDisposedException ) {
    // Ignore.  Control is disposed cannot update the UI.
  }
}

, ObjectDisposedException - , Invoke. , InvalidOperationException, .

+7

, "StopTimer" "TimerStopped". AutoReset false. Elapsed :

TimerStopped = false;
Invoke((MethodInvoker)delegate {
    // Work to do here.
});
if (!StopTimer)
    timer.Start();
else
    TimerStopped = true;

, , , , .

Now format the FormClosing event as follows:

if (!TimerStopped)
{
    StopTimer = true;
    Thread waiter = new Thread(new ThreadStart(delegate {
        while (!TimerStopped) { }
        Invoke((MethodInvoker)delegate { Close(); });
    }));
    waiter.Start();
    e.Cancel = true;
}
else
    timer.Dispose();

If the timer has not stopped yet, a thread starts to wait for it to do this, and then try closing the form again.

+1
source

All Articles