0

I found a suggested solution to the cross-thread exception issue in another posting and have used it my code below, but I am finding it erratic at best. My tests indicate that it's correct operation is at the mercy of a race condition so I was hoping someone might be able to point out the obvious or provide a more robust solution.

I have a program with two simple forms, where the sole purpose of Form1 is to open Form2. Form2 only contains a RichTextBox and has code that starts a thread that accesses that RichTextBox in an arbitrary way. When execution reaches the InvokeRequired property it is usually (but not always) false, so it goes directly to the RichTextBox access where a cross-thread exception is generated. However, when I call Thread.Sleep(...) just before testing the InvokeRequired property it appears to work properly. However, I hate to use Sleep for this purpose simply because it seems like a kluge that may not always work. Is there a reliable, yet reasonable, way to do cross-thread communication? Thanks.

public partial class Form1 : Form
{
   public Form1()
   {
      InitializeComponent();
      var form2 = new Form2();
      form2.ShowDialog();
   }
}

public partial class Form2 : Form
{
   public Form2()
   {
      InitializeComponent();
      Thread myThread = new Thread(new ThreadStart(myStartingMethod));
      myThread.Start();
   }

   void myStartingMethod()
   {
      Test("Hello world!\n");
   }

   private delegate void myCallback(string text);
   private void Test(string text)
   {
      // If I put Thread.Sleep(...something...) here it works better.
      if (myRichTextBox.InvokeRequired)
      {
         myCallback d = new myCallback(Test);
         Invoke(d, new Object[] { text });
      }
      else
      {
         // Cross-thread exception usually occurs, but not always.
         int x = myRichTextBox.TextLength;
      }
   }
}
BenevolentDeity
  • 693
  • 1
  • 4
  • 18
  • 1
    That's common pattern and it's proven to work. The problem here is no the pattern, but how you are trying to use it. Afaik it's because of control handle is not yet created, so not [`InvokeRequired`](https://referencesource.microsoft.com/#System.Windows.Forms/winforms/Managed/System/WinForms/Control.cs,3054) (if it's a single form), nor `Invoke` will work. Your `Sleep` obviously wait long enough for handle to be created, then it works. Rather then using constructor, try to use another event (not sure, `Shown` perhaps?) to test another thread. – Sinatr May 17 '18 at 10:35
  • Yes, it is an inevitable race. If you need it because you have no idea what thread a code runs on then you have big problems, excessively difficult to prove that such code is always thread-safe. But then again, *you always know*. Don't use it. And always make sure that you do not allow a form to close until worker threads are completed. [Look here](https://stackoverflow.com/a/1732361/17034). – Hans Passant May 17 '18 at 10:59

0 Answers0