Debugging Multithreaded Applications
by Peter Horwood, Shlomo Wygodny, and Martin Zardecki


Listing One
// Master Thread created earlier in the program
UINT MasterThreadProc(LPVOID pParam)
{
CString     cs_Out;
CThreadzDlg &MainDlg = *(CThreadzDlg *)pParam;

for (;;) {
/* Loop continuously checking to see if there is data in the input
   buffer */
  if (MainDlg.m_iInput1Bufferlen > 0) {
   /* Critical region here, while we use the buffer and the buffer length
      indicator Input1Thread could still be making changes to it, accordingly 
      we will get an inconsistent buffer and/or buffer length indicator */
  MainDlg.InTextBox().GetWindowText(cs_Out);
  cs_Out = cs_Out + CString(MainDlg.m_cInput1PseudoBuffer) + "\r\n";
  MainDlg.InTextBox().SetWindowText(cs_Out);
  MainDlg.m_iInput1Bufferlen = 0;
  // end of critical region
  }
 }
  return 0;
}
// This is a simulated keyboard monitoring thread
UINT Input1ThreadProc(LPVOID pParam)
{
  char  cKbdBuffer[MAX_PATH];
  CThreadzDlg   &MainDlg = *(CThreadzDlg *)pParam;
  // Assign arbitrary string to simulated keyboard
  strcpy(cKbdBuffer, "Hello World!!!");
  for (;;) {
  /* Fill up the pseudo-buffer at random interval but wait for buffer
     length variable to be zeroed by master thread */
  if ((rand()/(float)RAND_MAX * 100.0) < 70.0 &&
      MainDlg.m_iInput1Bufferlen == 0) {
/* MainDlg.m_iInput1Bufferlen should have been zeroed out by master
   thread Copy characters one at a time to simulate keystrokes */
   for (; MainDlg.m_iInput1Bufferlen <= strlen(cKbdBuffer);
          MainDlg.m_iInput1Bufferlen++) {
/* While we copy characters buffer length indicator is greater than 0
   MAsterThread will start using the buffer and reset the buffer
   length indicator to 0 again creating an inconsistent buffer and/or
   buffer length indicator. */
   MainDlg.m_cInput1PseudoBuffer[MainDlg.m_iInput1Bufferlen]
     = cKbdBuffer[MainDlg.m_iInput1Bufferlen];
   Sleep(200);
  }
 }
 Sleep(2000);
}
return 0;
}


Listing Two
// This is a simulated comm port/socket monitoring thread
UINT Input2ThreadProc(LPVOID pParam)
{
 UINT uiX;
 ...
/* This should actually cause a GPF the helper thread will access
    uiX after this function has terminated */
   m_pHelperThread = AfxBeginThread(HelperThreadProc, &uiX,
                     THREAD_PRIORITY_NORMAL, 0, 0, NULL);
   break;
 ...
return 0;
}
UINT HelperThreadProc(LPVOID pParam)
{
    //  uiX no longer exists
    // access violation/GPF here
     *((UINT *)pParam) = (UINT)5;
     return 0;
}






5


