bucket.c
来自「一本已经绝版的好书」· C语言 代码 · 共 479 行
C
479 行
/*************************************************************
Module name: Bucket.C
Notices: Copyright (c) 1995-1997 Jeffrey Richter
*************************************************************/
#include "..\CmnHdr.H" /* See Appendix C. */
#include <windows.h>
#include <windowsx.h>
#include <tchar.h>
#include <stdio.h> // For sprintf
#include <stdlib.h> // For rand
#include <process.h> // For _beginthreadex
#include "Resource.H"
#include "SWMRG.H"
//////////////////////////////////////////////////////////////
// single-writer/multiple-reader guard synchronization object
SWMRG g_SWMRG;
// Array of thread handles needed for process termination
HANDLE g_hThreads[5];
// Flag indicating when the threads should terminate
// The flag is volatile because it is changed asynchronously
long volatile g_lTerminate = 0;
// Window handle of dialog box.
HWND g_hwndDlg = NULL;
/////////////////////////////////////////////////////////////
////// Data and routines for manipulating the bucket ///////
/////////////////////////////////////////////////////////////
// Enumerated list of valid ball colors
typedef enum {
BC_FIRSTBALLCLR,
// BC_NULL indicates an empty space in the bucket.
BC_NULL = BC_FIRSTBALLCLR,
BC_BLACK,
BC_RED,
BC_GREEN,
BC_BLUE,
BC_WHITE,
BC_YELLOW,
BC_ORANGE,
BC_CYAN,
BC_GRAY,
BC_LASTBALLCLR = BC_GRAY
} BALLCOLOR;
// String list of valid ball colors
const TCHAR *szBallColors[] = {
NULL,
__TEXT("Black"),
__TEXT("Red"),
__TEXT("Green"),
__TEXT("Blue"),
__TEXT("White"),
__TEXT("Yellow"),
__TEXT("Orange"),
__TEXT("Cyan"),
__TEXT("Gray")
};
// Maximum number of balls in the bucket
#define MAX_BALLS 100
// Initially the bucket is empty.
// The bucket is volatile because its contents
// change asynchronously.
BALLCOLOR volatile g_Bucket[MAX_BALLS] = { BC_NULL };
////////////////////////////////////////////////////////////
void Bucket_AlterContents (void) {
// Add/remove a randomly colored ball to or from the bucket.
g_Bucket[rand() % MAX_BALLS] = (BALLCOLOR) (rand() % 10);
}
//////////////////////////////////////////////////////////////
void Bucket_DumpToLB (HWND hwndLB) {
int nBallNum;
int nBallColor[BC_LASTBALLCLR - BC_FIRSTBALLCLR + 1] =
{ 0 };
BALLCOLOR BallColor;
TCHAR szBuf[50];
// Calculate how many balls of each color are in the bucket.
for (nBallNum = 0; nBallNum < MAX_BALLS; nBallNum++) {
// Get the color of the nBallNum'th ball.
BallColor = g_Bucket[nBallNum];
// Increment the total for balls of this color.
nBallColor[BallColor]++;
}
// Empty the list box.
ListBox_ResetContent(hwndLB);
// Build the contents of the list box.
BallColor = BC_FIRSTBALLCLR;
for (; BallColor <= BC_LASTBALLCLR; BallColor++) {
if (szBallColors[BallColor] != NULL) {
_stprintf(szBuf, __TEXT("%s: %*s%2d"),
szBallColors[BallColor],
7 - lstrlen(szBallColors[BallColor]), __TEXT(" "),
nBallColor[BallColor]);
} else {
_stprintf(szBuf, __TEXT("Total: %2d"),
MAX_BALLS - nBallColor[BallColor]);
}
ListBox_AddString(hwndLB, szBuf);
}
}
/////////////////////////////////////////////////////////////
DWORD WINAPI Writer (LPVOID lpvParam) {
int nWriterNum = (int) lpvParam, nNumID;
switch (nWriterNum) {
case 1:
nNumID = IDC_WRITE1NUM;
break;
case 2:
nNumID = IDC_WRITE2NUM;
break;
default:
nNumID = 0; // We should never get here.
break;
}
// Continue looping until the process has been terminated.
while (!g_lTerminate) {
// Go to sleep for the user-defined amount of time.
Sleep(1000 *
GetDlgItemInt(g_hwndDlg, nNumID, NULL, FALSE));
// Wait until safe to write: no writers and no readers.
SWMRGWaitToWrite(&g_SWMRG, INFINITE);
// Write to the shared data (the bucket).
Bucket_AlterContents();
// Inform the other writers/readers that we are done.
SWMRGDoneWriting(&g_SWMRG);
}
return(0);
}
/////////////////////////////////////////////////////////////
DWORD WINAPI Reader (LPVOID lpvParam) {
int nReaderNum = (int) lpvParam, nNumID = 0;
HWND hwndLB = NULL;
// Get the window handle of the reader's display list box.
// Get the ID of the reader's number static control.
switch (nReaderNum) {
case 1:
nNumID = IDC_READ1NUM;
hwndLB = GetDlgItem(g_hwndDlg, IDC_READ1LIST);
break;
case 2:
nNumID = IDC_READ2NUM;
hwndLB = GetDlgItem(g_hwndDlg, IDC_READ2LIST);
break;
case 3:
nNumID = IDC_READ3NUM;
hwndLB = GetDlgItem(g_hwndDlg, IDC_READ3LIST);
break;
default:
nNumID = 0; // We should never get here.
hwndLB = NULL;
break;
}
// Continue looping until the process has been terminated.
while (!g_lTerminate) {
// Go to sleep for the user-defined amount of time.
Sleep(1000 *
GetDlgItemInt(g_hwndDlg, nNumID, NULL, FALSE));
// Wait until safe to read: no writers
SWMRGWaitToRead(&g_SWMRG, INFINITE);
// Read from the shared data (the bucket).
Bucket_DumpToLB(hwndLB);
// Inform the other writers/readers that we are done.
SWMRGDoneReading(&g_SWMRG);
}
return(0);
}
////////////////////////////////////////////////////////////
BOOL Dlg_OnInitDialog (HWND hwnd, HWND hwndFocus,
LPARAM lParam) {
DWORD dwThreadID;
int x;
// Associate an icon with the dialog box.
chSETDLGICONS(hwnd, IDI_BUCKET, IDI_BUCKET);
// Save the handle of the dialog box in a global so that
// the threads can easily gain access to it. This must
// be done before creating the threads.
g_hwndDlg = hwnd;
// Initialize the scroll bar values for the bucket writers.
ScrollBar_SetRange(GetDlgItem(hwnd, IDC_WRITE1SCRL),
0, 60, FALSE);
ScrollBar_SetPos(GetDlgItem(hwnd, IDC_WRITE1SCRL), 1, TRUE);
SetDlgItemInt(hwnd, IDC_WRITE1NUM, 1, FALSE);
ScrollBar_SetRange(GetDlgItem(hwnd, IDC_WRITE2SCRL),
0, 60, FALSE);
ScrollBar_SetPos(GetDlgItem(hwnd, IDC_WRITE2SCRL), 3, TRUE);
SetDlgItemInt(hwnd, IDC_WRITE2NUM, 3, FALSE);
// Initialize the scroll bar values for the bucket readers.
ScrollBar_SetRange(GetDlgItem(hwnd, IDC_READ1SCRL),
0, 60, FALSE);
ScrollBar_SetPos(GetDlgItem(hwnd, IDC_READ1SCRL), 2, TRUE);
SetDlgItemInt(hwnd, IDC_READ1NUM, 2, FALSE);
ScrollBar_SetRange(GetDlgItem(hwnd, IDC_READ2SCRL),
0, 60, FALSE);
ScrollBar_SetPos(GetDlgItem(hwnd, IDC_READ2SCRL), 4, TRUE);
SetDlgItemInt(hwnd, IDC_READ2NUM, 4, FALSE);
ScrollBar_SetRange(GetDlgItem(hwnd, IDC_READ3SCRL),
0, 60, FALSE);
ScrollBar_SetPos(GetDlgItem(hwnd, IDC_READ3SCRL), 7, TRUE);
SetDlgItemInt(hwnd, IDC_READ3NUM, 7, FALSE);
// Create the two writer and three reader threads.
// NOTE: these threads MUST be created AFTER all other
// synchronization objects.
for (x = 0; x <= 1; x++) {
g_hThreads[x] = chBEGINTHREADEX(NULL, 0, Writer,
(LPVOID) (x + 1), 0, &dwThreadID);
}
for (x = 2; x <= 4; x++) {
g_hThreads[x] = chBEGINTHREADEX(NULL, 0, Reader,
(LPVOID) (x - 1), 0, &dwThreadID);
}
return(TRUE);
}
////////////////////////////////////////////////////////////
void Dlg_OnHScroll (HWND hwnd, HWND hwndCtl,
UINT code, int pos) {
int posCrnt, posMin, posMax;
posCrnt = ScrollBar_GetPos(hwndCtl);
ScrollBar_GetRange(hwndCtl, &posMin, &posMax);
switch (code) {
case SB_LINELEFT:
posCrnt--;
break;
case SB_LINERIGHT:
posCrnt++;
break;
case SB_PAGELEFT:
posCrnt -= 10;
break;
case SB_PAGERIGHT:
posCrnt += 10;
break;
case SB_THUMBTRACK:
posCrnt = pos;
break;
case SB_LEFT:
posCrnt = 0;
break;
case SB_RIGHT:
posCrnt = posMax;
break;
}
if (posCrnt < 0)
posCrnt = 0;
if (posCrnt > posMax)
posCrnt = posMax;
ScrollBar_SetPos(hwndCtl, posCrnt, TRUE);
SetDlgItemInt(hwnd, GetDlgCtrlID(hwndCtl) - 1,
posCrnt, FALSE);
}
////////////////////////////////////////////////////////////
void Dlg_OnVScroll (HWND hwnd, HWND hwndCtl,
UINT code, int pos) {
int posCrnt, posMin, posMax;
posCrnt = ScrollBar_GetPos(hwndCtl);
ScrollBar_GetRange(hwndCtl, &posMin, &posMax);
switch (code) {
case SB_LINEUP:
posCrnt--;
break;
case SB_LINEDOWN:
posCrnt++;
break;
case SB_PAGEUP:
posCrnt -= 10;
break;
case SB_PAGEDOWN:
posCrnt += 10;
break;
case SB_THUMBTRACK:
posCrnt = pos;
break;
case SB_TOP:
posCrnt = 0;
break;
case SB_BOTTOM:
posCrnt = posMax;
break;
}
if (posCrnt < 0)
posCrnt = 0;
if (posCrnt > posMax)
posCrnt = posMax;
ScrollBar_SetPos(hwndCtl, posCrnt, TRUE);
SetDlgItemInt(hwnd, GetDlgCtrlID(hwndCtl) - 1,
posCrnt, FALSE);
}
////////////////////////////////////////////////////////////
void Dlg_OnCommand (HWND hwnd, int id,
HWND hwndCtl, UINT codeNotify) {
switch (id) {
case IDCANCEL:
EndDialog(hwnd, id);
break;
}
}
////////////////////////////////////////////////////////////
BOOL CALLBACK Dlg_Proc (HWND hwnd, UINT uMsg,
WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
chHANDLE_DLGMSG(hwnd, WM_INITDIALOG, Dlg_OnInitDialog);
chHANDLE_DLGMSG(hwnd, WM_COMMAND, Dlg_OnCommand);
chHANDLE_DLGMSG(hwnd, WM_HSCROLL, Dlg_OnHScroll);
chHANDLE_DLGMSG(hwnd, WM_VSCROLL, Dlg_OnVScroll);
}
return(FALSE);
}
////////////////////////////////////////////////////////////
int WINAPI _tWinMain (HINSTANCE hinstExe,
HINSTANCE hinstPrev, LPTSTR pszCmdLine, int nCmdShow) {
int x;
chWARNIFUNICODEUNDERWIN95();
// Initialize the single-writer/multiple-reader
// guard synchronization object. This must be done
// before any thread attempts to use it.
SWMRGInitialize(&g_SWMRG, NULL);
// Display the process's user interface.
DialogBox(hinstExe, MAKEINTRESOURCE(IDD_BUCKET),
NULL, Dlg_Proc);
// When the user shuts down the process, clean up.
// 1. Inform the threads that the process is terminating.
InterlockedIncrement((PLONG) &g_lTerminate);
// 2. Wait for all of the threads to terminate. This
// might take a long time because some threads might be
// sleeping and therefore not checking the g_lTerminate
// variable.
WaitForMultipleObjects(chDIMOF(g_hThreads), g_hThreads,
TRUE, INFINITE);
// 3. Close all of our handles to the threads.
for (x = 0; x < chDIMOF(g_hThreads); x++)
CloseHandle(g_hThreads[x]);
// 4. Delete the Single Writer/Multiple Reader Guard
// synchronization object. This must be done when it
// is known that no threads will attempt to use it.
SWMRGDelete(&g_SWMRG);
return(0);
}
/////////////////////// End Of File ////////////////////////
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?