tlsstat.c

来自「一本已经绝版的好书」· C语言 代码 · 共 250 行

C
250
字号
/************************************************************
Module name: TLSStat.C
Notices: Copyright (c) 1995-1997 Jeffrey Richter
************************************************************/


#include "..\CmnHdr.H"                  /* See Appendix C. */
#include <windows.h>
#include <windowsx.h>
#include <tchar.h>
#include <stdlib.h>            // For rand
#include <stdio.h>             // For sprintf
#include <process.h>           // For _beginthreadex
#include "Resource.H"


/////////////////////////////////////////////////////////////


// Structure used to pass data from one thread to another
typedef struct {
   int nThreadNum;      // The number used for recordkeeping
   int nNumCycles;      // Number of iterations in the loop
   DWORD dwCycleTime;   // Time spent in each loop iteration
} THREADDATA, *LPTHREADDATA;


// Global handle to list box window used for 
// logging execution
HWND g_hwndLogLB = NULL;


// Our global static TLS variable
// to hold each thread's start time
// The system will automatically allocate one of these
// for every thread created in this process.
__declspec(thread) DWORD gt_dwStartTime = 0;


/////////////////////////////////////////////////////////////

DWORD WINAPI ThreadFunc (LPVOID lpvThreadParm) {
   // The parameter passed to us is a pointer to a THREADDATA
   // structure.  Let's save it in a local variable.
   LPTHREADDATA lpThreadData = (LPTHREADDATA) lpvThreadParm;

   TCHAR szBuf[100];

   // Store the thread's start time in its very
   // own static TLS variable.
   gt_dwStartTime = GetTickCount();

   // Write a log entry stating that we're starting.
   _stprintf(szBuf, __TEXT("Thread started: %d"),
      lpThreadData->nThreadNum);
   ListBox_AddString(g_hwndLogLB, szBuf);
   ListBox_SetCurSel(g_hwndLogLB, 0);

   // Start doing some work....
   while (lpThreadData->nNumCycles--) {
      // Write to the log how many cycles this thread
      // has left before it dies and how long this thread
      // has been running.
      _stprintf(szBuf,
         __TEXT("Thread %d, Cycles left=%d, time running=%d"),
         lpThreadData->nThreadNum, lpThreadData->nNumCycles,
         GetTickCount() - gt_dwStartTime);

      ListBox_AddString(g_hwndLogLB, szBuf);

      // Sleep for awhile and let other threads run.
      Sleep(lpThreadData->dwCycleTime);
   }

   // This thread is done executing; write a log entry
   // that says so and displays the total execution time
   // of the thread.
   _stprintf(szBuf, __TEXT("Thread ended: %d, total time=%d"),
      lpThreadData->nThreadNum,
      GetTickCount() - gt_dwStartTime);
   ListBox_AddString(g_hwndLogLB, szBuf);

   // The thread is responsible for deleting the THREADDATA
   // structure that was allocated by the primary thread.
   HeapFree(GetProcessHeap(), 0, lpvThreadParm);

   return(0);
}


/////////////////////////////////////////////////////////////


BOOL Dlg_OnInitDialog (HWND hwnd, HWND hwndFocus,
   LPARAM lParam) {

   // Associate an icon with the dialog box.
   chSETDLGICONS(hwnd, IDI_TLSSTAT, IDI_TLSSTAT);

   // Default the thread number to 1.
   SetDlgItemInt(hwnd, IDC_THREADNUM, 1, FALSE);

   // Default the number of cycles to 10.
   SetDlgItemInt(hwnd, IDC_NUMCYCLES, 10, FALSE);

   // Default the maximum cycle time to 3 seconds.
   SetDlgItemInt(hwnd, IDC_CYCLETIME, 3, FALSE);

   // Save the handle of the dialog box in a global
   // variable so that it can be accessed easily from
   // the thread function.
   g_hwndLogLB = GetDlgItem(hwnd, IDC_LOG);

   // Let's start with the Create Thread
   // button having focus.
   SetFocus(GetDlgItem(hwnd, IDOK));

   // I set focus, so the Dialog Manager shouldn't.
   return(FALSE);
}


/////////////////////////////////////////////////////////////


void Dlg_OnCommand (HWND hwnd, int id, HWND hwndCtl,
   UINT codeNotify) {

   DWORD        dwIDThread;
   HANDLE       hThread;
   LPTHREADDATA lpThreadData;

   switch (id) {

      case IDC_CLEAR:
         // Reset the application.
         SetDlgItemInt(hwnd, IDC_THREADNUM, 1, FALSE);
         ListBox_ResetContent(g_hwndLogLB);
         break;

      case IDOK:
         // Allocate a block of memory that can be used to
         // give data from this thread to the new thread we
         // are about to create.
         lpThreadData = (LPTHREADDATA)
            HeapAlloc(GetProcessHeap(), 0, 
               sizeof(THREADDATA));

         if (lpThreadData == NULL) {
            // Memory could not be allocated; display message
            // box and break.
            chMB(__TEXT("Error creating ThreadData"));
            break;
         }

         // Fill the memory block with the data from 
         // the dialog box.
         lpThreadData->nThreadNum =
            GetDlgItemInt(hwnd, IDC_THREADNUM, NULL, FALSE);
         lpThreadData->nNumCycles =
            GetDlgItemInt(hwnd, IDC_NUMCYCLES, NULL, FALSE);

         // Multiply the cycle time by 1000
         // to convert to seconds.
         lpThreadData->dwCycleTime = (DWORD)
            (1000 * GetDlgItemInt(hwnd,
            IDC_CYCLETIME, NULL, FALSE));


         // Increment the thread number for the next thread.
         SetDlgItemInt(hwnd, IDC_THREADNUM,
            lpThreadData->nThreadNum + 1, FALSE);

         // Create the new thread and pass it the address of
         // our allocated memory block containing the
         // attributes that the thread should use.  The
         // thread is responsible for freeing the memory
         // block when it no longer needs it.

         hThread = chBEGINTHREADEX(NULL, 0, ThreadFunc,
                (LPVOID) lpThreadData, 0, &dwIDThread);

         if (hThread != NULL) {
            // If the thread was created successfully, close
            // the handle because this thread never needs
            // to refer to the new thread again.
            CloseHandle(hThread);

         } else {

            // The thread could not be created;
            // display message box and break.
            chMB(__TEXT("Error creating the new thread"));
            HeapFree(GetProcessHeap(), 0,
               (LPVOID) lpThreadData);
         }
         break;

      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);
   }
   return(FALSE);
}


/////////////////////////////////////////////////////////////


int WINAPI _tWinMain (HINSTANCE hinstExe,
   HINSTANCE hinstPrev, LPTSTR pszCmdLine, int nCmdShow) {

   TCHAR szBuf[100];

   chWARNIFUNICODEUNDERWIN95();

   // The primary thread also gets its own TLS copy
   // of the gt_dwStartTime variable.  Let's initialize it to
   // the time when the application started executing.
   gt_dwStartTime = GetTickCount();

   DialogBox(hinstExe, MAKEINTRESOURCE(IDD_TLSSTAT),
      NULL, Dlg_Proc);

   // The user has terminated the dialog box; let's show
   // how long the whole application has been running.
   _stprintf(szBuf,
      __TEXT("Total time running application=%d."),
      GetTickCount() - gt_dwStartTime);
   chMB(szBuf);

   return(0);
}


//////////////////////// End Of File ////////////////////////

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?