MFC - Đa luồng
Thư viện Microsoft Foundation Class (MFC) cung cấp hỗ trợ cho các ứng dụng đa luồng. Một luồng là một đường dẫn thực thi trong một tiến trình. Khi bạn khởi động Notepad, hệ điều hành sẽ tạo một quy trình và bắt đầu thực thi luồng chính của quy trình đó. Khi luồng này kết thúc, quá trình cũng vậy.
Bạn có thể tạo các chuỗi bổ sung trong ứng dụng của mình nếu bạn muốn. Tất cả các luồng trong ứng dụng MFC được biểu diễn bằng các đối tượng CWinThread. Trong hầu hết các tình huống, bạn thậm chí không cần phải tạo các đối tượng này một cách rõ ràng; thay vào đó, hãy gọi hàm trợ giúp khung AfxBeginThread, hàm này tạo đối tượng CWinThread cho bạn.
Chúng ta hãy xem xét một ví dụ đơn giản bằng cách tạo một ứng dụng dựa trên hộp thoại MFC mới.
Step 1 - Thay đổi Chú thích và ID của Điều khiển tĩnh thành Click on Start Thread button và IDC_STATIC_TEXT tương ứng.
Step 2 - Kéo hai nút và thêm trình xử lý sự kiện nhấp chuột cho các nút này.
Step 3 - Thêm biến điều khiển để điều khiển văn bản tĩnh.
Step 4 - Bây giờ thêm ba biến toàn cục sau vào đầu tệp CMFCMultithreadingDlg.cpp.
int currValue;
int maxValue;
BOOL stopNow;
Step 5 - Thêm thông báo WM_TIMER trong lớp CMFCMultithreadingDlg.
Đây là việc triển khai 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);
}
Step 6 - Bây giờ thêm một hàm mẫu để sử dụng trong AfxBeginThread trong lớp CMFCMultithreadingDlg.
UINT MyThreadProc(LPVOID Param) {
while (!stopNow && (currValue < maxValue)) {
currValue++;
Sleep(50); // would do some work here
}
return TRUE;
}
Step 7 - Đây là việc thực hiện xử lý sự kiện cho nút Start Thread, nút này sẽ bắt đầu luồng.
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
}
Step 8 - Đây là việc triển khai trình xử lý sự kiện cho nút Stop Thread, nút này sẽ dừng luồng.
void CMFCMultithreadingDlg::OnBnClickedButtonStop() {
// TODO: Add your control notification handler code here
stopNow = TRUE;
KillTimer(1234);
m_ctrlStatus.SetWindowText(L"Stopped");
}
Step 9 - Đây là tập tin nguồn hoàn chỉnh.
// 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");
}
Step 10 - Khi đoạn mã trên được biên dịch và thực thi, bạn sẽ thấy kết quả như sau.
Step 11 - Bây giờ bấm vào nút Start Thread.
Step 12- Nhấp vào nút Stop Thread. Nó sẽ dừng chuỗi.