title: MFC application hangs in thread signaled for termination
body: <p>I'm writing an app in MFC with a background worker thread (created via <code>_beginthreadex</code>) and UI thread. A button is clicked from the UI thread to begin and end the worker thread. It starts the background thread if the <code>m_threadRunning</code> flag is false, and stops the background thread if it is true. The way I go about stopping the thread is I set the <code>m_threadRunning</code> flag to false and call <code>WaitForSingleObject</code> to let the background thread finish what it is doing.</p>
  
  <p>My app has four different states. I had the first three states working properly, and adding the fourth state is what caused my problem. For the fourth state I want to be able to sample the desktop and send average RGB values to the COM port for processing. When in any of the first three states, if I want to stop execution of sending data to the COM port, it will terminate normally and without problems. If I am in the fourth state and click "stop", the application will hang since I have no time out on my call to <code>WaitForSingleObject</code>. </p>
  
  <p>I also have a custom <code>CEdit</code> box <code>CColorEdit</code> that shows the current RGB values. I update this from the background thread when I'm in either state 3 or 4 (since they both change the colors dynamically). I've narrowed down the problem to a call to when I'm setting the color in which I call either <code>Invalidate</code> or <code>RedrawWindow</code>.</p>
  
  <p>I've come up with a few solutions, but I don't like any of them and would rather understand what is causing the problem since my goal in writing this in MFC is to learn and understand MFC. Here is what has resolved the problem:</p>
  
  <ol>
  <li>I call Sleep() in my worker thread already at about 60 samples/second. Changing this to a lower value, like 30 samples/second, resolved the problem most of the time.</li>
  <li>I poll <code>m_threadRunning</code> in my worker thread to check if the thread should be terminated. If I poll it after sampling the screen but before updating the edit control, this resolves the problem most of the time.</li>
  <li>I do a timeout of 5 seconds when calling <code>WaitForSingleObject</code> and call TerminateThread to manually kill the thread when it fails to wait, this resolves the problem all of the time. This is my solution in place for now.</li>
  </ol>
  
  <p>Here are the relevant code bits (I lock around any use of outBytes):</p>
  
  <pre><code>void CLightControlDlg::UpdateOutputLabel()
  {
      CSingleLock locker(&amp;m_crit);
      locker.Lock();
  
      m_outLabel.SetColor(outBytes[1], outBytes[2], outBytes[3]); //the call to this freezes the program
  
      CString str;
      str.Format(L"R = %d; G = %d; B = %d;", outBytes[1], outBytes[2], outBytes[3]);
      m_outLabel.SetWindowText(str);
  }
  </code></pre>
  
  <p>This section of code is for terminating the worker thread</p>
  
  <pre><code>m_threadRunning = false;
  locker.Unlock(); //release the lock...
  //omitted re-enabling of some controls
  //normally this is just WaitForSingleObject(m_threadHand, INFINITE);
  if(WaitForSingleObject(m_threadHand, 5000) == WAIT_TIMEOUT) 
  {
      MessageBox(L"There was an error cancelling the I/O operation to the COM port. Forcing a close.");
      TerminateThread(m_threadHand, 0);
  }
  CloseHandle(m_threadHand);
  CloseHandle(m_comPort);
  m_threadHand = INVALID_HANDLE_VALUE;
  m_comPort = INVALID_HANDLE_VALUE;
  </code></pre>
  
  <p>The code in my derived edit control that updates the text color:</p>
  
  <pre><code>void SetColor(byte r, byte g, byte b)
  {
      _r = r;
      _g = g;
      _b = b;
      br.DeleteObject();
      br.CreateSolidBrush(RGB(r,g,b));
      Invalidate(); //RedrawWindow() freezes as well
  }
  </code></pre>
  
  <p>And finally, the code for my thread procedure:</p>
  
  <pre><code>unsigned int __stdcall SendToComProc(void * param)
  {
      CLightControlDlg *dlg = (CLightControlDlg*)param;
      while(1)
      {
          if(!dlg-&gt;IsThreadRunning())
              break;
  
          switch(dlg-&gt;GetCurrentState())
          {
          case TransitionColor: //state 3
              dlg-&gt;DoTransition();
              dlg-&gt;UpdateOutputLabel();
              break;
          case ScreenColor: //state 4
              dlg-&gt;DoGetScreenAverages();
              //if(!dlg-&gt;IsThreadRunning()) break; //second poll to IsThreadRunning()
              dlg-&gt;UpdateOutputLabel();
              break;
          }
          dlg-&gt;SendToCom();
          Sleep(17); // Sleep for 1020 / 60 = 17 = ~60samples/sec
      }
      return 0;
  }
  </code></pre>
  
  <p>Any help you can provide is greatly appreciated!</p>