Multithreading in C++ - The Thread Control Panel (Page 5 of 11 )
The code for the thread control panel is shown here. This file is called tcp.cpp.
// A thread control panel. #include <map> #include <windows.h> #include "panel.h" using namespace std; const int NUMPRIORITIES = 5; const int OFFSET = 2; // Array of strings for priority list box. char priorities[NUMPRIORITIES][80] = { "Lowest", "Below Normal", "Normal", "Above Normal", "Highest" }; // A Thread Control Panel Class. class ThrdCtrlPanel { // Information about the thread under control. struct ThreadInfo { HANDLE hThread; // handle of thread int priority; // current priority bool suspended; // true if suspended ThreadInfo(HANDLE ht, int p, bool s) { hThread = ht; priority = p; suspended = s; } }; // This map holds a ThreadInfo for each // active thread control panel. static map<HWND, ThreadInfo> dialogmap; public: // Construct a control panel. ThrdCtrlPanel(HINSTANCE hInst, HANDLE hThrd); // The control panel's callback function. static LRESULT CALLBACK ThreadPanel(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); }; // Define static member dialogmap. map<HWND, ThrdCtrlPanel::ThreadInfo> ThrdCtrlPanel::dialogmap; // Create a thread control panel. ThrdCtrlPanel::ThrdCtrlPanel(HINSTANCE hInst, HANDLE hThrd) { ThreadInfo ti(hThrd, GetThreadPriority(hThrd)+OFFSET, false); // Owner window is desktop. HWND hDialog = CreateDialog(hInst, "ThreadPanelDB", NULL, (DLGPROC) ThreadPanel); // Put info about this dialog box in the map. dialogmap.insert(pair<HWND, ThreadInfo>(hDialog, ti)); // Set the control panel's title. char str[80] = "Control Panel for Thread "; char str2[4]; _itoa(dialogmap.size(), str2, 10); strcat(str, str2); SetWindowText(hDialog, str); // Offset each dialog box instance. MoveWindow(hDialog, 30*dialogmap.size(), 30*dialogmap.size(), 300, 250, 1); // Update priority setting in the list box. SendDlgItemMessage(hDialog, IDD_LB, LB_SETCURSEL, (WPARAM) ti.priority, 0); // Increase priority to ensure control. You can // change or remove this statement based on your // execution environment. SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL); } // Thread control panel dialog box callback function. LRESULT CALLBACK ThrdCtrlPanel::ThreadPanel(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { int i; HWND hpbRes, hpbSus, hpbTerm; switch(message) { case WM_INITDIALOG: // Initialize priority list box. for(i=0; i<NUMPRIORITIES i++) { SendDlgItemMessage(hwnd, IDD_LB, LB_ADDSTRING, 0, (LPARAM) priorities[i]); } // Set suspend and resume buttons for thread. hpbSus = GetDlgItem(hwnd, IDD_SUSPEND); hpbRes = GetDlgItem(hwnd, IDD_RESUME); EnableWindow(hpbSus, true); // enable Suspend EnableWindow(hpbRes, false); // disable Resume return 1; case WM_COMMAND: map<HWND, ThreadInfo>::iterator p = dialogmap.find(hwnd); switch(LOWORD(wParam)) { case IDD_TERMINATE: TerminateThread(p->second.hThread, 0); // Disable Terminate button. hpbTerm = GetDlgItem(hwnd, IDD_TERMINATE); } EnableWindow(hpbTerm, false); // disable // Disable Suspend and Resume buttons. hpbSus = GetDlgItem(hwnd, IDD_SUSPEND); hpbRes = GetDlgItem(hwnd, IDD_RESUME); EnableWindow(hpbSus, false); // disable Suspend EnableWindow(hpbRes, false); // disable Resume return 1; case IDD_SUSPEND: SuspendThread(p->second.hThread); // Set state of the Suspend and Resume buttons. hpbSus = GetDlgItem(hwnd, IDD_SUSPEND); hpbRes = GetDlgItem(hwnd, IDD_RESUME); EnableWindow(hpbSus, false); // disable Suspend EnableWindow(hpbRes, true); // enable Resume p->second.suspended = true; return 1; case IDD_RESUME: ResumeThread(p->second.hThread); // Set state of the Suspend and Resume buttons. hpbSus = GetDlgItem(hwnd, IDD_SUSPEND); hpbRes = GetDlgItem(hwnd, IDD_RESUME); /' EnableWindow(hpbSus, true); // enable Suspend /' EnableWindow(hpbRes, false); // disable Resume p->second.suspended = false; return 1; case IDD_LB: // If a list box entry was clicked, // then change the priority. if(HIWORD(wParam)==LBN_DBLCLK) { p->second.priority = SendDlgItemMessage(hwnd, IDD_LB, LB_GETCURSEL,/' 0, 0); SetThreadPriority(p->second.hThread, p->second.priority-OFFSET); } return 1; case IDCANCEL: // If thread is suspended when panel is closed, // then resume thread to prevent deadlock. if(p->second.suspended) { ResumeThread(p->second.hThread); p->second.suspended = false; } // Remove this thread from the list. dialogmap.erase(hwnd); // Close the panel. DestroyWindow(hwnd);? return 1; } } return 0; }
The control panel requires the following resource file, called tcp.rc:
#include <windows.h> #include "panel.h" ThreadPanelDB DIALOGEX 20, 20, 140, 110 CAPTION "Thread Control Panel" STYLE WS_BORDER | WS_VISIBLE | WS_POPUP | WS_CAPTION | WS_SYSMENU { DEFPUSHBUTTON "Done", IDCANCEL, 55, 80, 33, 14 PUSHBUTTON "Terminate", IDD_TERMINATE, 10, 20, 42, 12 PUSHBUTTON "Suspend", IDD_SUSPEND, 10, 35, 42, 12 PUSHBUTTON "Resume", IDD_RESUME, 10, 50, 42, 12 LISTBOX IDD_LB, 65, 20, 63, 42, LBS_NOTIFY | WS_VISIBLE | WS_BORDER | WS_VSCROLL | WS_TABSTOP CTEXT "Thread Priority", IDD_TEXT1, 65, 8, 64, 10 CTEXT "Change State", IDD_TEXT2, 0, 8, 64, 10 }
The control panel uses the following header file called panel.h:
#define IDD_LB 200 #define IDD_TERMINATE 202 #define IDD_SUSPEND 204 #define IDD_RESUME 206 #define IDD_TEXT1 208 #define IDD_TEXT2 209
To use the thread control panel, follow these steps:
Include tcp.cpp in your program.
Include tcp.rc in your program’s resource file.
Create the thread or threads that you want to control.
Instantiate a ThrdCtrlPanel object for each thread.
Each ThrdCtrlPanel object links a thread with a dialog box that controls it. For large projects in which multiple files need access to ThrdCtrlPanel, you will need to use a header file called tcp.h that contains the declaration for ThrdCtrlPanel. Here is tcp.h:
// A header file for the ThrdCtrlPanel class. class ThrdCtrlPanel { public: // Construct a control panel. ThrdCtrlPanel(HINSTANCE hInst, HANDLE hThrd); // The control panel's callback function. static LRESULT CALLBACK ThreadPanel(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); };
Please enable JavaScript to view the comments powered by Disqus. blog comments powered by