title: Why does C# thread die?
body: <p>This is my 1st C# project so I may be doing something obviously improper in the code below.
  I am using .NET, WinForms (I think), and this is a desktop application until I get the bugs out.
  <code>UpdateGui()</code> uses <code>Invoke((MethodInvoker)delegate</code> to update various GUI controls based on received serial data and
  sends a <code>GetStatus()</code> command out the serial port 4 times a second.
  Thread <code>Read()</code> reads the response from serial port whenever it arrives which should be near immediate.
  <code>SerialPortFixer</code> is a <code>SerialPort</code> <code>IOException</code> Workaround in C# I found at 
  <a href="http://zachsaw.blogspot.com/2010/07/serialport-ioexception-workaround-in-c.html" rel="nofollow">http://zachsaw.blogspot.com/2010/07/serialport-ioexception-workaround-in-c.html</a>.</p>
  
  <p>After one or both threads die I'll see something like 
  <code>The thread 0x1288 has exited with code 0 (0x0)</code>.
  in the debug code output.</p>
  
  <p>Why do UpdateGui() and/or Read() eventually die?</p>
  
  <pre><code>public partial class UpdateStatus : Form
  {
      private readonly byte[] Command = new byte[32];
      private readonly byte[] Status = new byte[32];
      readonly Thread readThread;
      private static readonly Mutex commandMutex = new Mutex();
      private static readonly Mutex statusMutex = new Mutex();
      ...
  
      public UpdateStatus()
      {
          InitializeComponent();
          SerialPortFixer.Execute("COM2");
          if (serialPort1.IsOpen)
          {
              serialPort1.Close();
          }
          try
          {
              serialPort1.Open();
          }
          catch (Exception e)
          {
              labelWarning.Text = LOST_COMMUNICATIONS + e;
              labelStatus.Text = LOST_COMMUNICATIONS + e;
              labelWarning.Visible = true;
          }
          readThread = new Thread(Read);
          readThread.Start();
          new Timer(UpdateGui, null, 0, 250);
      }
      static void ProcessStatus(byte[] status)
      {
          Status.State = (State) status[4];
          Status.Speed = status[6]; // MSB
          Status.Speed *= 256;
          Status.Speed += status[5];
          var Speed = Status.Speed/GEAR_RATIO;
          Status.Speed = (int) Speed;
          ...
      }
      public void Read()
      {
          while (serialPort1 != null)
          {
              try
              {
                  serialPort1.Read(Status, 0, 1);
                  if (Status[0] != StartCharacter[0]) continue;
                  serialPort1.Read(Status, 1, 1);
                  if (Status[1] != StartCharacter[1]) continue;
                  serialPort1.Read(Status, 2, 1);
                  if (Status[2] != (int)Command.GetStatus) continue;
                  serialPort1.Read(Status, 3, 1);
                  ...
                  statusMutex.WaitOne();
                  ProcessStatus(Status);
                  Status.update = true;
                  statusMutex.ReleaseMutex();
              }
              catch (Exception e)
              {
                  Console.WriteLine(@"ERROR! Read() " + e);
              }
          }
      }
      public void GetStatus()
      {
          const int parameterLength = 0; // For GetStatus
          statusMutex.WaitOne();
          Status.update = false;
          statusMutex.ReleaseMutex();
          commandMutex.WaitOne();
          if (!SendCommand(Command.GetStatus, parameterLength))
          {
              Console.WriteLine(@"ERROR! SendCommand(GetStatus)");
          }
          commandMutex.ReleaseMutex();
      }
      private void UpdateGui(object x)
      {
          try
          {                
              Invoke((MethodInvoker)delegate
              {
                  Text = DateTime.Now.ToLongTimeString();
                  statusMutex.WaitOne();
                  if (Status.update)
                  {
                      if (Status.Speed &gt; progressBarSpeed.Maximum)
                      {
                          Status.Speed = progressBarSpeed.Maximum;
                      }
                      progressBarSpeed.Value = Status.Speed;
                      labelSpeed.Text = Status.Speed + RPM;
                      ...
                  }
                  else
                  {
                      labelWarning.Text = LOST_COMMUNICATIONS;
                      labelStatus.Text = LOST_COMMUNICATIONS;
                      labelWarning.Visible = true;
                  }
                  statusMutex.ReleaseMutex();
                  GetStatus();
              });
          }
          catch (Exception e)
          {
              Console.WriteLine(@"ERROR! UpdateGui() " + e);
          }
      }
  }
  </code></pre>