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:
#define IDM_THREAD 100
#define IDM_HELP 101
#define IDM_PANEL 102
#define IDM_EXIT 103
The resource file required by the program is shown here:
#include <windows.h>
#include "thrdapp.h"
#include "tcp.rc"
ThreadAppMenu MENU
{
POPUP "&Threads" {
MENUITEM "&Start Threads\tF2", IDM_THREAD
MENUITEM "&Control Panels\tF3", IDM_PANEL
MENUITEM "E&xit\tCtrl+X", IDM_EXIT
}
MENUITEM "&Help", IDM_HELP
}
ThreadAppMenu ACCELERATORS
{
VK_F1, IDM_HELP, VIRTKEY
VK_F2, IDM_THREAD, VIRTKEY
VK_F3, IDM_PANEL, VIRTKEY
"^X", IDM_EXIT
}
Next: A Multithreaded Garbage Collector >>
More C++ Articles
More By McGraw-Hill/Osborne
|
This article is taken from chapter three of The Art of C++, written by Herbert Schildt (McGraw-Hill/Osborne, 2004; ISBN: 0072255129). Check it out at your favorite bookstore. Buy this book now.
|
|