Question

A control is accessed by two worker threads, the 2nd before the first has completed it's work on the control. The second thread (9) gets InvokeRequired == false, and the first thread (17) then gets the exception when calling .Refresh on a child-control.

Is this expected behavior? What exactly causes a thread to see a control's InvokeRequired as true/false?
And finally, what would be a good solution.. Put a lock on all invoke statements, and make them call a separate method instead (to avoid deadlock obviously) ?

private void OnHistoryUpdate(object sender)
{
    Console.WriteLine("<< Invoke? " + this.InvokeRequired   + " " + Thread.CurrentThread.ManagedThreadId );

    if (this.InvokeRequired)
        this.Invoke(new Action<object>(OnHistoryUpdate), sender);  

    LoadTimeSeries(this.Interval);
    Console.WriteLine(">> Invoke? " + this.InvokeRequired   + " " + Thread.CurrentThread.ManagedThreadId);

}

output:

<< Invoke? True Thread: 17
<< Invoke? False Thread:  9
>> Invoke? False Thread:  9
Was it helpful?

Solution

Your code updates the control twice:

  • Using the call to Invoke, which delegates another call to OnHistoryUpdate. This is safe because Invoke marshals execution to the UI thread.
  • After the call to Invoke. Invoke executes synchronously and when it returns your code will call LoadTimeSeries a second time, this time unsafely (it doesn't check InvokeRequired again).

I would change the method as below, and also consider using BeginInvoke instead so the worker thread doesn't block.

private void OnHistoryUpdate(object sender)
{
    Console.WriteLine("<< Invoke? " + this.InvokeRequired   + " " + Thread.CurrentThread.ManagedThreadId );

    if (this.InvokeRequired)
        this.Invoke(new Action<object>(OnHistoryUpdate), sender);
    else  
        LoadTimeSeries(this.Interval);

    Console.WriteLine(">> Invoke? " + this.InvokeRequired   + " " + Thread.CurrentThread.ManagedThreadId);    
}

OTHER TIPS

If you call Refresh on a control that requires invoke from you thread without using invoke it is expected to get an exception. Make sure that you do not do this and you'll be fine. This is all that is needed.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top