Учебники

MFC – Многопоточность

Библиотека Microsoft Foundation Class (MFC) обеспечивает поддержку многопоточных приложений. Поток – это путь выполнения внутри процесса. Когда вы запускаете Блокнот, операционная система создает процесс и начинает выполнение основного потока этого процесса. Когда этот поток завершается, процесс тоже.

Вы можете создать дополнительные темы в своем приложении, если хотите. Все потоки в приложениях MFC представлены объектами CWinThread. В большинстве ситуаций вам даже не нужно явно создавать эти объекты; вместо этого вызовите вспомогательную функцию фреймворка AfxBeginThread, которая создаст для вас объект CWinThread.

Давайте рассмотрим простой пример, создав новое приложение на основе диалогового окна MFC.

Шаг 1 – Измените заголовок и идентификатор статического элемента управления на Нажмите кнопку «Начать тему» и IDC_STATIC_TEXT соответственно.

Шаг 2 – Перетащите две кнопки и добавьте обработчики событий щелчка для этих кнопок.

Кнопка «Начать тему»

Шаг 3 – Добавьте переменную управления для статического контроля текста.

Шаг 4 – Теперь добавьте следующие три глобальные переменные в начале файла CMFCMultithreadingDlg.cpp.

int currValue;
int maxValue;
BOOL stopNow;

Шаг 5 – Добавьте сообщение WM_TIMER в класс CMFCMultithreadingDlg.

Вот реализация OnTimer ()

void CMFCMultithreadingDlg::OnTimer(UINT_PTR nIDEvent) {
   // TODO: Add your message handler code here and/or call default
   CString sStatusMsg;
   sStatusMsg.Format(L"Running: %d", currValue);
   m_ctrlStatus.SetWindowText(sStatusMsg);

   CDialogEx::OnTimer(nIDEvent);
}

Шаг 6 – Теперь добавьте пример функции для использования в AfxBeginThread в классе CMFCMultithreadingDlg.

UINT MyThreadProc(LPVOID Param) {
   while (!stopNow && (currValue < maxValue)) {
      currValue++;
      Sleep(50);     // would do some work here
   }
   
   return TRUE;
}

Шаг 7 – Вот реализация обработчика события для кнопки Start Thread, которая запустит поток.

void CMFCMultithreadingDlg::OnBnClickedButtonStart() {
   // TODO: Add your control notification handler code here
   currValue = 0;
   maxValue = 5000;
   stopNow = 0;
   m_ctrlStatus.SetWindowText(L"Starting...");
   SetTimer(1234, 333, 0); // 3 times per second

   AfxBeginThread(MyThreadProc, 0); // <<== START THE THREAD
}

Шаг 8 – Вот реализация обработчика события для кнопки Stop Thread, которая остановит поток.

void CMFCMultithreadingDlg::OnBnClickedButtonStop() {
   
   // TODO: Add your control notification handler code here
   stopNow = TRUE;
   KillTimer(1234);
   m_ctrlStatus.SetWindowText(L"Stopped");
}

Шаг 9 – Вот полный исходный файл.

// MFCMultithreadingDlg.cpp : implementation file
//

#include "stdafx.h"
#include "MFCMultithreading.h"
#include "MFCMultithreadingDlg.h"
#include "afxdialogex.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

// CMFCMultithreadingDlg dialog

int currValue;
int maxValue;
BOOL stopNow;

CMFCMultithreadingDlg::CMFCMultithreadingDlg(CWnd* pParent /* = NULL*/)
   : CDialogEx(IDD_MFCMULTITHREADING_DIALOG, pParent) {
   m_hIcon = AfxGetApp() -> LoadIcon(IDR_MAINFRAME);
}
void CMFCMultithreadingDlg::DoDataExchange(CDataExchange* pDX) {
   CDialogEx::DoDataExchange(pDX);
   DDX_Control(pDX, IDC_STATIC_TEXT, m_ctrlStatus);
}

BEGIN_MESSAGE_MAP(CMFCMultithreadingDlg, CDialogEx)
   ON_WM_PAINT()
   ON_WM_QUERYDRAGICON()
   ON_BN_CLICKED(IDC_BUTTON_START,
      &CMFCMultithreadingDlg::OnBnClickedButtonStart)
   ON_WM_TIMER()
   ON_BN_CLICKED(IDC_BUTTON_STOP,
      &CMFCMultithreadingDlg::OnBnClickedButtonStop)
END_MESSAGE_MAP()

// CMFCMultithreadingDlg message handlers

BOOL CMFCMultithreadingDlg::OnInitDialog() {
   CDialogEx::OnInitDialog();

   // Set the icon for this dialog. The framework does this automatically
   // when the application's main window is not a dialog
   SetIcon(m_hIcon, TRUE);        // Set big icon
   SetIcon(m_hIcon, FALSE);       // Set small icon

   // TODO: Add extra initialization here

   return TRUE; // return TRUE unless you set the focus to a control
}

// If you add a minimize button to your dialog, you will need the code below
// to draw the icon. For MFC applications using the document/view model,
// this is automatically done for you by the framework.

void CMFCMultithreadingDlg::OnPaint() {
   if (IsIconic()) {
      CPaintDC dc(this); // device context for painting
      SendMessage(WM_ICONERASEBKGND,
         reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
			
      // Center icon in client rectangle
      int cxIcon = GetSystemMetrics(SM_CXICON);
      int cyIcon = GetSystemMetrics(SM_CYICON);
      CRect rect;
      GetClientRect(&rect);
      int x = (rect.Width() - cxIcon + 1) / 2;
      int y = (rect.Height() - cyIcon + 1) / 2;

      // Draw the icon
      dc.DrawIcon(x, y, m_hIcon);
   }else {
      CDialogEx::OnPaint();
   }
}
// The system calls this function to obtain the cursor to display while the user drags
// the minimized window.
HCURSOR CMFCMultithreadingDlg::OnQueryDragIcon() {
   return static_cast<HCURSOR>(m_hIcon);
}

UINT /*CThreadDlg::*/MyThreadProc(LPVOID Param) //Sample function for using in
AfxBeginThread {
   while (!stopNow && (currValue < maxValue)) {
      currValue++;
      Sleep(50); // would do some work here
   }
   return TRUE;
}
void CMFCMultithreadingDlg::OnBnClickedButtonStart() {
   // TODO: Add your control notification handler code here
   currValue = 0;
   maxValue = 5000;
   stopNow = 0;
   m_ctrlStatus.SetWindowText(L"Starting...");
   SetTimer(1234, 333, 0); // 3 times per second

   AfxBeginThread(MyThreadProc, 0); // <<== START THE THREAD
}

void CMFCMultithreadingDlg::OnTimer(UINT_PTR nIDEvent) {
   // TODO: Add your message handler code here and/or call default
   CString sStatusMsg;
   sStatusMsg.Format(L"Running: %d", currValue);
   m_ctrlStatus.SetWindowText(sStatusMsg);

   CDialogEx::OnTimer(nIDEvent);
}

void CMFCMultithreadingDlg::OnBnClickedButtonStop() {
   // TODO: Add your control notification handler code here
   stopNow = TRUE;
   KillTimer(1234);
   m_ctrlStatus.SetWindowText(L"Stopped");
}

Шаг 10 – Когда приведенный выше код скомпилирован и выполнен, вы увидите следующий вывод.

Многопоточность

Шаг 11 – Теперь нажмите на кнопку «Начать тему».

Начать тему

Шаг 12 – Нажмите кнопку «Остановить поток». Это остановит поток.