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 + -
显示快捷键?