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