Home arrow C++ arrow Page 5 - Multithreading in C++
C++

Multithreading in C++


Multithreading is growing in importance in modern programming for a variety of reasons, not the least of which being that Windows supports multithreading. While C++ does not feature built-in support for multithreading, it can be used to created multithreaded programs, which is the subject of this article. It is taken from chapter three of The Art of C++, written by Herbert Schildt (McGraw-Hill/Osborne, 2004; ISBN: 0072255129).

Author Info:
By: McGraw-Hill/Osborne
Rating: 5 stars5 stars5 stars5 stars5 stars / 229
July 14, 2005
TABLE OF CONTENTS:
  1. · Multithreading in C++
  2. · An Overview of the Windows Thread Functions
  3. · Priority Classes
  4. · The Windows Synchronization Objects
  5. · The Thread Control Panel
  6. · A Closer Look at the Thread Control Panel
  7. · Demonstrating the Control Panel
  8. · A Multithreaded Garbage Collector
  9. · Synchronizing Access to gclist
  10. · The Entire Multithreaded Garbage Collector
  11. · Using the Multithreaded Garbage Collector

print this article
SEARCH DEVARTICLES

Multithreading in C++ - The Thread Control Panel
(Page 5 of 11 )

The code for the thread control panel is shown here. This file is called tcp.cpp.

// 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;
}

The control panel requires the following resource file, called tcp.rc:

#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
}

The control panel uses the following header file called panel.h:

#define IDD_LB           200
#define IDD_TERMINATE    202
#define IDD_SUSPEND      204
#define IDD_RESUME       206
#define IDD_TEXT1        208
#define IDD_TEXT2        209

To use the thread control panel, follow these steps:

  1. Include tcp.cpp in your program.

  2. Include tcp.rc in your programís resource file.

  3. Create the thread or threads that you want to control.

  4. Instantiate a ThrdCtrlPanel object for each thread.

Each ThrdCtrlPanel object links a thread with a dialog box that controls it. For large projects in which multiple files need access to ThrdCtrlPanel, you will need to use a header file called tcp.h that contains the declaration for ThrdCtrlPanel. Here is tcp.h:

// 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);
};


blog comments powered by Disqus
C++ ARTICLES

- Intel Threading Building Blocks
- Threading Building Blocks with C++
- Video Memory Programming in Text Mode
- More Tricks to Gain Speed in Programming Con...
- Easy and Efficient Programming for Contests
- Preparing For Programming Contests
- Programming Contests: Why Bother?
- Polymorphism in C++
- Overview of Virtual Functions
- Inheritance in C++
- Extending the Basic Streams in C++
- Using Stringstreams in C++
- Custom Stream Manipulation in C++
- General Stream Manipulation in C++
- Serialize Your Class into Streams in C++

Watch our Tech Videos 
Dev Articles Forums 
 RSS  Articles
 RSS  Forums
 RSS  All Feeds
Write For Us 
Weekly Newsletter
 
Developer Updates  
Free Website Content 
Contact Us 
Site Map 
Privacy Policy 
Support 

Developer Shed Affiliates

 




© 2003-2017 by Developer Shed. All rights reserved. DS Cluster - Follow our Sitemap
Popular Web Development Topics
All Web Development Tutorials