/////////////////////////////////////////////////////////////// // // // nosynch.cpp - demonstration of threads with no // // ver 1.0 synchronization // // // // Language: Visual C, ver 6.0 // // Platform: Micron Dual Pentium Pro 200, Win NT 4.0 // // Application: CSE691 Project #1 // // Author: Jim Fawcett, Instructor, CSE691, Fall '99 // // CST 2-187, Syracuse Univ, (315) 443-3948 // // fawcett@ecs.syr.edu // // // /////////////////////////////////////////////////////////////// /* Module Operations: ================== This module demonstrates (dangerous) use of threads without synchronizing access to a shared instance of the C++ string class. The main thread creates two worker threads that each run in forever loops, modifying the contents of the shared string. Sometimes when this program runs it crashes as soon as the second worker thread starts modifying the shared string. This because the string state gets corrupted when the first thread is put to sleep (before finishing its modification) and the second thread starts its work. Whether this happens depends on the non-deterministic timing of the individual threads. Note that when the program first starts up it displays message boxes showing what threads are currently active in the important program functions, e.g., WinMain, WndProc, and thProc. */ /////////////////////////////////////////////////////////////// // build process // /////////////////////////////////////////////////////////////// // required files: // // nosynch.cpp, Win32utils.h, Win32utils.cpp // // // // building in IDE: // // - build Win32 Application project // // - add these files to project // // - change Project\Settings\C/C++\Category: // // Code Generation = Debug Mulitthreaded // // - compile, line, and run // /////////////////////////////////////////////////////////////// /* Maintenance History: ==================== ver 1.0 : 06 Nov 99 - first release */ // #include #include #include #include "Win32utils.h" using namespace std; //----< forward reference of windows processing function >----- LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); //----< entry point >------------------------------------------ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { HWND hwnd; // declare handle to window MSG msg; // declare message structure showCurrentThreadID(NULL,"WinMain"); // build window class structure and register it WNDCLASSEX wndclass; static char szAppName[] = "synchronization"; wndclass.cbSize = sizeof (wndclass); wndclass.style = CS_HREDRAW | CS_VREDRAW; wndclass.lpfnWndProc = WndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = hInstance; wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION); wndclass.hCursor = LoadCursor (NULL, IDC_ARROW); wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wndclass.lpszMenuName = NULL; wndclass.lpszClassName = szAppName; wndclass.hIconSm = LoadIcon (NULL, IDI_APPLICATION); RegisterClassEx (&wndclass); // create main window, show it, and start message loop hwnd = CreateWindow (szAppName, szAppName, WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, 200, 200, 550, 200, NULL, NULL, hInstance, NULL); ShowWindow (hwnd, iCmdShow); UpdateWindow (hwnd); while (GetMessage (&msg, NULL, 0, 0)) { TranslateMessage (&msg); DispatchMessage (&msg); } return msg.wParam; } // //----< structure for passing arguments to thread function >--- struct thARGS { HWND hwnd; string str; }; //----< thread function >-------------------------------------- // // here is where shared string text gets corrupted // if there is no program synchronization of access // unsigned int __stdcall thProc(void *args) { static string text; // shared resource thARGS *pArgs = (thARGS*)args; // structure of arguments showCurrentThreadID(pArgs->hwnd,"thProc"); // each thread adds its own word to string const int RESTART_SIZE = 60; while(1) { if(text.size() < RESTART_SIZE) text += pArgs->str; else text = pArgs->str; // this user-defined message passes a pointer to the // text string and asks windows to repaint client area PostMessage(pArgs->hwnd,WM_USER,(WPARAM)&text,0); // Sleep(50); } return 0; } // //----< process messages for main window >--------------------- LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { HDC hDC; PAINTSTRUCT ps; RECT rect; GetClientRect(hwnd,&rect); HANDLE thHandle[2] = { NULL, NULL }; unsigned int thID1, thID2; static struct thARGS args1, args2; static string *pString = NULL; char *temp = "no synchronization"; switch (iMsg) { case WM_CREATE : showCurrentThreadID(hwnd,"WndProc"); args1.hwnd = hwnd; args1.str = "first "; args2.hwnd = hwnd; args2.str = "second "; thHandle[0] = (HANDLE)_beginthreadex(NULL,0,thProc,&args1,0,&thID1); thHandle[1] = (HANDLE)_beginthreadex(NULL,0,thProc,&args2,0,&thID2); return 0; case WM_SIZE : rect.right = LOWORD (lParam); rect.bottom = HIWORD (lParam); return 0; case WM_USER : pString = (string*)wParam; InvalidateRect(hwnd,&rect,TRUE); return 0; case WM_PAINT : hDC = BeginPaint(hwnd,&ps); TextOut(hDC,10,10,temp,strlen(temp)); if(pString == NULL) return 0; TextOut(hDC,30,70,pString->c_str(),pString->size()); EndPaint(hwnd,&ps); return 0; case WM_DESTROY : CloseHandle(thHandle[0]); CloseHandle(thHandle[1]); PostQuitMessage (0); return 0; } return DefWindowProc (hwnd, iMsg, wParam, lParam); }