Библиотека 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 — Нажмите кнопку «Остановить поток». Это остановит поток.