📄 chap3.lst
字号:
listing 1
// 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;
}
listing 2
#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
}
listing 3
#define IDD_LB 200
#define IDD_TERMINATE 202
#define IDD_SUSPEND 204
#define IDD_RESUME 206
#define IDD_TEXT1 208
#define IDD_TEXT2 209
listing 4
// 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);
};
listing 5
// 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;
}
listing 6
#define IDM_THREAD 100
#define IDM_HELP 101
#define IDM_PANEL 102
#define IDM_EXIT 103
listing 7
#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
}
listing 8
// A garbage collector that runs as a back ground task.
#include <iostream>
#include <list>
#include <typeinfo>
#include <cstdlib>
#include <windows.h>
#include <process.h>
using namespace std;
// To watch the action of the garbage collector, define DISPLAY.
// #define DISPLAY
// Exception thrown when an attempt is made to
// use an Iter that exceeds the range of the
// underlying object.
//
class OutOfRangeExc {
// Add functionality if needed by your application.
};
// Exception thrown when a time-out occurs
// when waiting for access to hMutex.
//
class TimeOutExc {
// Add functionality if needed by your application.
};
// An iterator-like class for cycling through arrays
// that are pointed to by GCPtrs. Iter pointers
// ** do not ** participate in or affect garbage
// collection. Thus, an Iter pointing to
// some object does not prevent that object
// from being recycled.
//
template <class T> class Iter {
T *ptr; // current pointer value
T *end; // points to element one past end
T *begin; // points to start of allocated array
unsigned length; // length of sequence
public:
Iter() {
ptr = end = begin = NULL;
length = 0;
}
Iter(T *p, T *first, T *last) {
ptr = p;
end = last;
begin = first;
length = last - first;
}
// Return length of sequence to which this
// Iter points.
unsigned size() { return length; }
// Return value pointed to by ptr.
// Do not allow out-of-bounds access.
T &operator*() {
if( (ptr >= end) || (ptr < begin) )
throw OutOfRangeExc();
return *ptr;
}
// Return address contained in ptr.
// Do not allow out-of-bounds access.
T *operator->() {
if( (ptr >= end) || (ptr < begin) )
throw OutOfRangeExc();
return ptr;
}
// Prefix ++.
Iter operator++() {
ptr++;
return *this;
}
// Prefix --.
Iter operator--() {
ptr--;
return *this;
}
// Postfix ++.
Iter operator++(int notused) {
T *tmp = ptr;
ptr++;
return Iter<T>(tmp, begin, end);
}
// Postfix --.
Iter operator--(int notused) {
T *tmp = ptr;
ptr--;
return Iter<T>(tmp, begin, end);
}
// Return a reference to the object at the
// specified index. Do not allow out-of-bounds
// access.
T &operator[](int i) {
if( (i < 0) || (i >= (end-begin)) )
throw OutOfRangeExc();
return ptr[i];
}
// Define the relational operators.
bool operator==(Iter op2) {
return ptr == op2.ptr;
}
bool operator!=(Iter op2) {
return ptr != op2.ptr;
}
bool operator<(Iter op2) {
return ptr < op2.ptr;
}
bool operator<=(Iter op2) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -