Multithreading is growing in importance in modern programming for a variety of reasons, not the least of which being that Windows supports multithreading. While C++ does not feature built-in support for multithreading, it can be used to created multithreaded programs, which is the subject of this article. It is taken from chapter three of The Art of C++, written by Herbert Schildt (McGraw-Hill/Osborne, 2004; ISBN: 0072255129).
Multithreading in C++ - Demonstrating the Control Panel (Page 7 of 11 )
Here is a program that includes the thread control panel and demonstrates its use. Sample output is shown in Figure 3-2. The program creates a main window and defines two child threads. When started, these threads simply count from 0 to 50,000, displaying the count in the main window. These threads can be controlled by activating a thread control panel.
To use the program, first begin execution of the threads by selecting Start Threads from the Threads menu (or by pressing F2) and then activate the thread control panels by selecting Control Panels from the Threads menu (or by pressing F3). Once the control panels are active, you can experiment with different priority settings and so on.
Figure 3-2.Sample output from the thread control panel sample program
NOTE It is beyond the scope of this book to teach Windows programming. However, the operation of this sample program is straightforward and should be easily understood by all Windows programmers.
// Demonstrate the thread control panel. #include <windows.h> #include <process.h> #include "thrdapp.h" #include "tcp.cpp" const int MAX = 500000; LRESULT CALLBACK WindowFunc(HWND, UINT, WPARAM, LPARAM); unsigned __stdcall MyThread1(void * param); unsigned __stdcall MyThread2(void * param); char str[255]; // holds output strings unsigned tid1, tid2; // thread IDs HANDLE hThread1, hThread2; // thread handles HINSTANCE hInst; // instance handle int WINAPI WinMain(HINSTANCE hThisInst, HINSTANCE hPrevInst, LPSTR args, int winMode) { HWND hwnd; MSG msg; WNDCLASSEX wcl; HACCEL hAccel; // Define a window class. wcl.cbSize = sizeof(WNDCLASSEX); wcl.hInstance = hThisInst; // handle to this instance wcl.lpszClassName = "MyWin"; // window class name wcl.lpfnWndProc = WindowFunc; // window function wcl.style = 0; // default style wcl.hIcon = LoadIcon(NULL, IDI_APPLICATION); // large icon wcl.hIconSm = NULL; // use small version of large icon wcl.hCursor = LoadCursor(NULL, IDC_ARROW); // cursor style wcl.lpszMenuName = "ThreadAppMenu"; // main menu wcl.cbClsExtra = 0; // no extra memory needed wcl.cbWndExtra = 0; // Make the window background white. wcl.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH); // Register the window class. if(!RegisterClassEx(&wcl)) return 0; /* Now that a window class has been registered, a window can be created. */ hwnd = CreateWindow( wcl.lpszClassName, // name of window class "Using a Thread Control Panel", // title WS_OVERLAPPEDWINDOW, // window style - normal CW_USEDEFAULT, // X coordinate - let Windows decide CW_USEDEFAULT, // Y coordinate - let Windows decide 260, // width 200, // height NULL, // no parent window NULL, // no override of class menu hThisInst, // instance handle NULL // no additional arguments ); hInst = hThisInst; // save instance handle // Load the keyboard accelerators. hAccel = LoadAccelerators(hThisInst, "ThreadAppMenu"); // Display the window. ShowWindow(hwnd, winMode); UpdateWindow(hwnd); // Create the message loop. while(GetMessage(&msg, NULL, 0, 0)) { if(!TranslateAccelerator(hwnd, hAccel, &msg)) { TranslateMessage(&msg); // translate keyboard messages DispatchMessage(&msg); // return control to Windows } } return msg.wParam; } /* This function is called by Windows and is passed messages from the message queue. */ LRESULT CALLBACK WindowFunc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { int response; switch(message) { case WM_COMMAND: switch(LOWORD(wParam)) { case IDM_THREAD: // create the threads hThread1 = (HANDLE) _beginthreadex(NULL, 0, MyThread1, (void *) hwnd, 0, &tid1); hThread2 = (HANDLE) _beginthreadex(NULL, 0, MyThread2, (void *) hwnd, 0, &tid2); break; case IDM_PANEL: // activate control panel ThrdCtrlPanel(hInst, hThread1); ThrdCtrlPanel(hInst, hThread2); break; case IDM_EXIT: response = MessageBox(hwnd, "Quit the Program?", "Exit", MB_YESNO); if(response == IDYES) PostQuitMessage(0); break; case IDM_HELP: MessageBox(hwnd, "F1: Help\nF2: Start Threads\nF3: Panel", "Help", MB_OK); break; } break; case WM_DESTROY: // terminate the program PostQuitMessage(0); break; default: return DefWindowProc(hwnd, message, wParam, lParam); } return 0; } // First thread. unsigned __stdcall MyThread1(void * param) { int i; HDC hdc; for(i=0; i<MAX; i++) { wsprintf(str, "Thread 1: loop # %5d ", i); hdc = GetDC((HWND) param); TextOut(hdc, 1, 1, str, lstrlen(str)); ReleaseDC((HWND) param, hdc); } return 0; } // Second thread. unsigned __stdcall MyThread2(void * param) { int i; HDC hdc; for(i=0; i<MAX; i++) { wsprintf(str, "Thread 2: loop # %5d ", i); hdc = GetDC((HWND) param); TextOut(hdc, 1, 20, str, lstrlen(str)); ReleaseDC((HWND) param, hdc); } return 0; }
This program requires the header file thrdapp.h, shown here: