Solved: The destination thread no longer exists exception – C#

2016-11-08

You will get System.ComponentModel.InvalidAsynchronousStateException (The destination thread no longer exists.) if a UI component gets disposed or the UI thread EXITs while a different thread is in the middle of invoking a change on the same UI component.

This usually happens when a user closes a window (form) that has been updated by a different thread.

You can make the form to gracefully close itself after waiting for existing invokes by following steps.

1 – Intercept the thread exiting code (e.g. form closing event can be used to intercept a form close)
2 – Advice any methods that creates invokes to stop creating any new invokes (can be achieved by setting a flag e.g. stopInvoking flag in the example)
3 – Wait for any existing invokes to finish (set another flag before each invoke and reset it after invoke finishes and use it to determine if an invoke is in progress e.g. invokeInProgress flag in example)

As seen in the example, you may make the stopInvoking flag public so any clients that try to use the Form may know that you are no longer in business so they also get to handle the situation gracefully.

flags

private bool invokeInProgress = false;
private bool stopInvoking = false
public bool ShuttingDown { get { return stopInvoking; } }

invoking code

        public void AddItem(string newItem)
        {

            if (listView1.InvokeRequired)
            {
                if (stopInvoking != true) // don't start new invokes if the flag is set
                {
                    invokeInProgress = true;  // let the form know if an invoke has started

                    listView1.Invoke(new Action(() => addItem(newItem)));

                    invokeInProgress = false;  // the invoke is complete
                }

                return;
            }

            listView1.Items.Add(newItem);
            listView1.Items[listView1.Items.Count - 1].EnsureVisible();
        }

intercepting and managing form closing event

        private async void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (invokeInProgress)
            {
                e.Cancel = true;  // cancel the original event 

                stopInvoking = true; // advise to stop taking new work

                // now wait until current invoke finishes
                await Task.Factory.StartNew(() =>
                                {
                                    while (invokeInProgress);  
                                });

                // now close the form
                this.Close();
            }
        }

example client code that can recognise the problem and handle accordingly

        static void Main()
        {
            Form1 frm = new Form1();

            Task.Factory.StartNew(() => frm.ShowDialog(), TaskCreationOptions.LongRunning);

            int i = 0;
            while (i < 2000)
            {
                if (frm.ShuttingDown != true)  // the clients can also be notified and allowed to handle the UI disruption
                {
                    frm.AddItem(Guid.NewGuid().ToString());
                }
                else
                {
                    MessageBox.Show("Form is closing. Stopping the process.");
                    break;
                }

                i++;
            }

            MessageBox.Show("Program completed! i=" + i.ToString());
        }

Download source code (VS 2013 solution)
background-thread-already-closed

This entry was posted in C#.Net, Microsoft .Net Framework and tagged , , , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *