critsecs.c
来自「一本已经绝版的好书」· C语言 代码 · 共 381 行
C
381 行
/************************************************************
Module name: CritSecs.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 <process.h> // For _beginthreadex
#include "Resource.H"
//////////////////////////////////////////////////////////////
// Global variables
// g_fTerminate is set to TRUE when the dialog box is
// dismissed. It indicates to the worker threads that they
// need to terminate. It is volatile because it can change
// at any time.
volatile BOOL g_fTerminate = FALSE;
HWND g_hwnd;
HANDLE g_hThread[2]; // Counter[0] & Display[1] threads
// The data that needs protecting
TCHAR g_szNumber[10] = __TEXT("0");
// The critical section used to protect the data
CRITICAL_SECTION g_CriticalSection;
//////////////////////////////////////////////////////////////
// Add a string to a list box.
void AddToListBox (LPCTSTR szBuffer) {
HWND hwndDataBox = GetDlgItem(g_hwnd, IDC_DATABOX);
int x = ListBox_AddString(hwndDataBox, szBuffer);
ListBox_SetCurSel(hwndDataBox, x);
if (ListBox_GetCount(hwndDataBox) > 100)
ListBox_DeleteString(hwndDataBox, 0);
}
//////////////////////////////////////////////////////////////
// Thread to increment the protected counter data
DWORD WINAPI CounterThread (LPVOID lpThreadParameter) {
unsigned int nNumber, nDigit;
BOOL fSyncChecked;
while (!g_fTerminate) {
// Get the status of the Synchronize check box
// and save it.
fSyncChecked =
IsDlgButtonChecked(g_hwnd, IDC_SYNCHRONIZE);
if (fSyncChecked) {
// If the user wants us synchronized, do it.
EnterCriticalSection(&g_CriticalSection);
}
// Convert the string number to an integer and add 1.
_stscanf(g_szNumber, __TEXT("%d"), &nNumber);
nNumber++;
// Convert the new integer back to a string.
nDigit = 0;
while (nNumber != 0) {
// Put a digit into the string.
g_szNumber[nDigit++] = (TCHAR)
(__TEXT('0') + (nNumber % 10));
// A call to Sleep here tells the system that we want
// to relinquish the remainder of our time slice to
// another thread. This call is needed for
// single-CPU systems so that the results of the
// synchronization or lack thereof are obvious.
// Normally, your programs would NOT call Sleep here.
Sleep(0);
// Get ready to get the next digit.
nNumber /= 10;
}
// All digits converted to characters.
// Terminate the string.
g_szNumber[nDigit] = 0;
// Characters were generated in reverse order;
// reverse the string.
// Call _strrev if ANSI, Call _wcsrev if Unicode.
_tcsrev(g_szNumber);
if (fSyncChecked) {
// If the user wants synchronization, do it.
// In earlier versions of this program, I was calling
// IsDlgButtonChecked as I did earlier instead of
// using the fSyncChecked variable. This caused
// problems because the user could check or uncheck
// the Synchronize check box in between the calls to
// EnterCriticalSection and LeaveCriticalSection.
// This meant that my thread was sometimes leaving a
// critical section that it had never entered. And my
// thread was sometimes entering a critical section
// that it had never left.
LeaveCriticalSection(&g_CriticalSection);
}
// If the user wants to display something
// after each iteration, do it.
if (IsDlgButtonChecked(g_hwnd, IDC_SHOWCNTRTHRD))
AddToListBox(__TEXT("Cntr: Increment"));
}
return(0); // We get here when the window is dismissed.
}
///////////////////////////////////////////////////////////////
// Thread to add the current value of
// the counter (data) to the list box
DWORD WINAPI DisplayThread (LPVOID lpThreadParameter) {
BOOL fSyncChecked;
TCHAR szBuffer[50];
while (!g_fTerminate) {
// Determine whether the user wants the threads
// to be synchronized.
fSyncChecked =
IsDlgButtonChecked(g_hwnd, IDC_SYNCHRONIZE);
if (fSyncChecked)
EnterCriticalSection(&g_CriticalSection);
// Construct a string with the string form of the number.
_stprintf(szBuffer, __TEXT("Dspy: %s"), g_szNumber);
if (fSyncChecked)
LeaveCriticalSection(&g_CriticalSection);
// Add the string form of the number to the list box.
AddToListBox(szBuffer);
}
return(0); // We get here when the window is dismissed.
}
//////////////////////////////////////////////////////////////
BOOL Dlg_OnInitDialog (HWND hwnd, HWND hwndFocus,
LPARAM lParam) {
HWND hWndCtl;
DWORD dwThreadID;
// Associate an icon with the dialog box.
chSETDLGICONS(hwnd, IDI_CRITSECS, IDI_CRITSECS);
// 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_hwnd = hwnd;
// Initialize the critical section. This must also be
// done before any threads try to use it.
InitializeCriticalSection(&g_CriticalSection);
// Create our counter thread and let it start running.
g_hThread[0] = chBEGINTHREADEX(NULL, 0,
CounterThread, NULL, 0, &dwThreadID);
// Create our display thread and let it start running.
g_hThread[1] = chBEGINTHREADEX(NULL, 0,
DisplayThread, NULL, 0, &dwThreadID);
// Fill the Process Priority Class combo box and select
// Normal.
hWndCtl = GetDlgItem(hwnd, IDC_PRIORITYCLASS);
ComboBox_AddString(hWndCtl, __TEXT("Idle"));
ComboBox_AddString(hWndCtl, __TEXT("Normal"));
ComboBox_AddString(hWndCtl, __TEXT("High"));
ComboBox_AddString(hWndCtl, __TEXT("Realtime"));
ComboBox_SetCurSel(hWndCtl, 1); // Normal
// Fill the Display Thread Priority
// combo box and select Normal.
hWndCtl = GetDlgItem(hwnd, IDC_DSPYTHRDPRIORITY);
ComboBox_AddString(hWndCtl, __TEXT("Idle"));
ComboBox_AddString(hWndCtl, __TEXT("Lowest"));
ComboBox_AddString(hWndCtl, __TEXT("Below normal"));
ComboBox_AddString(hWndCtl, __TEXT("Normal"));
ComboBox_AddString(hWndCtl, __TEXT("Above normal"));
ComboBox_AddString(hWndCtl, __TEXT("Highest"));
ComboBox_AddString(hWndCtl, __TEXT("Timecritical"));
ComboBox_SetCurSel(hWndCtl, 3); // Normal
// Fill the Counter Thread Priority
// combo box and select Normal.
hWndCtl = GetDlgItem(hwnd, IDC_CNTRTHRDPRIORITY);
ComboBox_AddString(hWndCtl, __TEXT("Idle"));
ComboBox_AddString(hWndCtl, __TEXT("Lowest"));
ComboBox_AddString(hWndCtl, __TEXT("Below normal"));
ComboBox_AddString(hWndCtl, __TEXT("Normal"));
ComboBox_AddString(hWndCtl, __TEXT("Above normal"));
ComboBox_AddString(hWndCtl, __TEXT("Highest"));
ComboBox_AddString(hWndCtl, __TEXT("Timecritical"));
ComboBox_SetCurSel(hWndCtl, 3); // Normal
return(TRUE);
}
//////////////////////////////////////////////////////////////
void Dlg_OnDestroy (HWND hwnd) {
// When the dialog box is destroyed, signal the worker
// threads to terminate.
g_fTerminate = TRUE;
// Resume the worker threads in case they're paused.
ResumeThread(g_hThread[0]);
ResumeThread(g_hThread[1]);
}
//////////////////////////////////////////////////////////////
void Dlg_OnCommand (HWND hwnd, int id, HWND hwndCtl,
UINT codeNotify) {
HANDLE hThread;
DWORD dw;
switch (id) {
case IDCANCEL:
EndDialog(hwnd, id);
break;
case IDC_PRIORITYCLASS:
if (codeNotify != CBN_SELCHANGE)
break;
// User is changing priority class.
switch (ComboBox_GetCurSel(hwndCtl)) {
case 0:
dw = IDLE_PRIORITY_CLASS;
break;
case 1:
default:
dw = NORMAL_PRIORITY_CLASS;
break;
case 2:
dw = HIGH_PRIORITY_CLASS;
break;
case 3:
dw = REALTIME_PRIORITY_CLASS;
break;
}
SetPriorityClass(GetCurrentProcess(), dw);
break;
case IDC_DSPYTHRDPRIORITY:
case IDC_CNTRTHRDPRIORITY:
if (codeNotify != CBN_SELCHANGE)
break;
switch (ComboBox_GetCurSel(hwndCtl)) {
case 0:
dw = (DWORD) THREAD_PRIORITY_IDLE;
break;
case 1:
dw = (DWORD) THREAD_PRIORITY_LOWEST;
break;
case 2:
dw = (DWORD) THREAD_PRIORITY_BELOW_NORMAL;
break;
case 3:
default:
dw = (DWORD) THREAD_PRIORITY_NORMAL;
break;
case 4:
dw = (DWORD) THREAD_PRIORITY_ABOVE_NORMAL;
break;
case 5:
dw = (DWORD) THREAD_PRIORITY_HIGHEST;
break;
case 6:
dw = (DWORD) THREAD_PRIORITY_TIME_CRITICAL;
break;
}
// User is changing the relative priority
// of one of the threads.
hThread = (id == IDC_CNTRTHRDPRIORITY) ?
g_hThread[0] : g_hThread[1];
SetThreadPriority(hThread, dw);
break;
case IDC_PAUSE:
// User is pausing or resuming both threads.
if (Button_GetCheck(hwndCtl)) {
SuspendThread(g_hThread[0]);
SuspendThread(g_hThread[1]);
} else {
ResumeThread(g_hThread[0]);
ResumeThread(g_hThread[1]);
}
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_DESTROY, Dlg_OnDestroy);
chHANDLE_DLGMSG(hwnd, WM_COMMAND, Dlg_OnCommand);
}
return(FALSE);
}
///////////////////////////////////////////////////////////////
int WINAPI _tWinMain (HINSTANCE hinstExe,
HINSTANCE hinstPrev, LPTSTR pszCmdLine, int nCmdShow) {
chWARNIFUNICODEUNDERWIN95();
DialogBox(hinstExe, MAKEINTRESOURCE(IDD_CRITSECS),
NULL, Dlg_Proc);
// Wait for both worker threads to terminate
WaitForMultipleObjects(2, g_hThread, TRUE, INFINITE);
// Close our handles to the worker threads
CloseHandle(g_hThread[0]);
CloseHandle(g_hThread[1]);
// The worker threads can no longer be using the
// critical section, so delete it.
DeleteCriticalSection(&g_CriticalSection);
return(0);
}
///////////////////////// End Of File /////////////////////////
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?