/////////////////////////////////////////////////////////////// // // // prsynch.cpp - demo of pocesses sharing data through a // // ver 1.0 memory mapped file and synchronizing // // access to the data with a named mutex // // // // 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 // // // /////////////////////////////////////////////////////////////// // References: // /////////////////////////////////////////////////////////////// // - Beginning Windows NT Programming, J.Templeman, // // WROX Press, 1998 // // - Advanced Windows, J.Richter, Microsoft Press, 1997 // // - Programming Windows, C.Petzold, Microsoft Press, 1999 // // - Win32 System Services, M.Brain, Prentice-Hall, 1996 // /////////////////////////////////////////////////////////////// // build process // /////////////////////////////////////////////////////////////// // required files: // // prsynch.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 #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 // build window class structure WNDCLASSEX wndclass; static char szAppName[] = "synchronization across processes"; 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); // register window class RegisterClassEx (&wndclass); // create main window at specified location with specified size hwnd = CreateWindow (szAppName, szAppName, WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, 200, 200, 550, 200, NULL, NULL, hInstance, NULL); // display window ShowWindow (hwnd, iCmdShow); UpdateWindow (hwnd); // start message loop while (GetMessage (&msg, NULL, 0, 0)) { TranslateMessage (&msg); DispatchMessage (&msg); } return msg.wParam; } // //----< increment process count stamp >------------------------ // // - When 1st process calls this function it places a stamp at // the beginning of the memory mapped file and places its // process number (equal to zero) just after the stamp. // - When a 2nd or later process calls this function it detects // the stamp and simply increments the process number following // the stamp // int incStamp(char *pChars) { // set stamp if(strstr(pChars,"prsync") == NULL) { strcpy(pChars,"prsync"); pChars[6] = ' '; pChars[7] = '0'; pChars[8] = ':'; pChars[9] = '\0'; return 0; } // get process number from file, increment it, and store it back istrstream in(pChars+6); int processNumber; in >> processNumber; string temp = makeString("",++processNumber); // ostrstream out; // out << ++processNumber << ends; // char *temp = out.str(); pChars[7] = temp[0]; if(temp[1] != '\0') pChars[8] = temp[1]; else pChars[8] = ':'; pChars[9] = '\0'; return processNumber; } // //----< structure for passing arguments to thread function >--- struct thARGS { HWND hwnd; // handle to display window HANDLE hMutex; // handle to named mutex int procNum; // number of this process char *pChars; // pointer to beginning of memory mapped file int MapSize; // size of memory mapped file }; //----< thread function >-------------------------------------- // // This process appends its number to string contained in // a memory mapped file. If the string is longer than a // certain size then it is truncated and the Appending starts // over again. // unsigned int __stdcall thProc(void *args) { thARGS *pArgs = (thARGS*)args; // get access to arguments char *temp = pArgs->pChars + 9; // point to appending area // make string out of process number ostrstream out; out << ' ' << (pArgs->procNum) << ends; char *add = out.str(); // - loop forever appending process number to shared string // - truncate string if it reaches end of mapped area in memory while(1) { WaitForSingleObject(pArgs->hMutex,INFINITE); if(strlen(temp) < pArgs->MapSize - 1 - strlen(add)) strcat(temp,add); else strcpy(temp,add); ReleaseMutex(pArgs->hMutex); // this user-defined message asks windows to repaint client area PostMessage(pArgs->hwnd,WM_USER,(WPARAM)add,0); Sleep(50); } return 0; } // //----< get handle to memory mapped file >--------------------- HANDLE getMemoryMappedFileHandle(int MapSize) { HANDLE hMMFile; hMMFile = CreateFileMapping( (HANDLE)(0xFFFFFFFF), // not a disk file NULL, // security attributes PAGE_READWRITE, // access control 0, // high byte of file size MapSize, // low byte of file size "SharedString" // object name used by another ); // process to get a handle if(hMMFile == NULL) showSysError("CreateFileMapping",GetLastError()); return hMMFile; } //----< get pointer to beginning of file map >----------------- char* getPointerToFileMap(HANDLE hMMFile, int MapSize) { char *pChars; pChars = (char*)MapViewOfFile( hMMFile, // handle to mmfile FILE_MAP_ALL_ACCESS, // access control 0,0, // high and low bytes of offset MapSize // size of map in bytes ); return pChars; } //----< process messages for main window >--------------------- LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { HDC hDC; // device context and paint structure PAINTSTRUCT ps; // needed for painting text to screen RECT rect; // defines client area for painting GetClientRect(hwnd,&rect); HANDLE thHandle = 0; // handle to thread using shared memory unsigned int thID1; // thread ID static struct thARGS args1; // arguments to thread function static HANDLE hMMFile = 0; // memory mapped file handle (shared memory) const int MapSize = 70; // size of mapped area static char *pChars = NULL; // pointer to beginning of mapped area HANDLE hMutex = 0; // handle to named mutex, used to // synchronize access to shared memory // const int MAXWRITE = 70; static char szText[MAXWRITE]; char *label1 = "sharing through a memory mapped file"; char *label2 = "synchronized with a named mutex"; switch (iMsg) { case WM_CREATE : hMMFile = getMemoryMappedFileHandle(MapSize); pChars = getPointerToFileMap(hMMFile,MapSize); hMutex = CreateMutex(NULL,FALSE,"MappedFileMutex"); if(hMutex == NULL) showSysError("mutex creation",GetLastError()); args1.hwnd = hwnd; args1.hMutex = hMutex; args1.procNum = incStamp(pChars); args1.pChars = pChars; args1.MapSize = MapSize; thHandle = (HANDLE)_beginthreadex(NULL,0,thProc,&args1,0,&thID1); return 0; case WM_SIZE : rect.right = LOWORD (lParam); rect.bottom = HIWORD (lParam); return 0; case WM_USER : strncpy(szText,"Process ",MAXWRITE); strncat(szText,(char*)wParam,MAXWRITE); InvalidateRect(hwnd,&rect,TRUE); return 0; case WM_PAINT : hDC = BeginPaint(hwnd,&ps); TextOut(hDC,10,10,szText,strlen(szText)); TextOut(hDC,10,30,label1,strlen(label1)); TextOut(hDC,10,50,label2,strlen(label2)); if(pChars == NULL) return 0; WaitForSingleObject(hMutex,INFINITE); TextOut(hDC,30,80,pChars,strlen(pChars)); ReleaseMutex(hMutex); EndPaint(hwnd,&ps); return 0; case WM_DESTROY : CloseHandle(hMMFile); CloseHandle(thHandle); CloseHandle(hMutex); PostQuitMessage (0); return 0; } return DefWindowProc (hwnd, iMsg, wParam, lParam); }