MFC - Multithreading
La libreria Microsoft Foundation Class (MFC) fornisce il supporto per le applicazioni multithread. Un thread è un percorso di esecuzione all'interno di un processo. Quando si avvia Blocco note, il sistema operativo crea un processo e inizia a eseguire il thread principale di tale processo. Quando questo thread termina, così fa il processo.
È possibile creare thread aggiuntivi nella propria applicazione, se lo si desidera. Tutti i thread nelle applicazioni MFC sono rappresentati dagli oggetti CWinThread. Nella maggior parte delle situazioni, non è nemmeno necessario creare esplicitamente questi oggetti; chiama invece la funzione di supporto del framework AfxBeginThread, che crea l'oggetto CWinThread per te.
Esaminiamo un semplice esempio creando una nuova applicazione basata sulla finestra di dialogo MFC.
Step 1 - Modificare la didascalia e l'ID del controllo statico in Click on Start Thread button e IDC_STATIC_TEXT rispettivamente.
Step 2 - Trascina due pulsanti e aggiungi gestori di eventi clic per questi pulsanti.
Step 3 - Aggiungi variabile di controllo per il controllo del testo statico.
Step 4 - Ora aggiungi le seguenti tre variabili globali all'inizio del file CMFCMultithreadingDlg.cpp.
int currValue;
int maxValue;
BOOL stopNow;
Step 5 - Aggiungere il messaggio WM_TIMER nella classe CMFCMultithreadingDlg.
Ecco l'implementazione di 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 - Ora aggiungi una funzione di esempio da utilizzare in AfxBeginThread nella classe CMFCMultithreadingDlg.
UINT MyThreadProc(LPVOID Param) {
while (!stopNow && (currValue < maxValue)) {
currValue++;
Sleep(50); // would do some work here
}
return TRUE;
}
Step 7 - Ecco l'implementazione del gestore di eventi per il pulsante Start Thread, che avvierà il 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
}
Step 8 - Ecco l'implementazione del gestore eventi per il pulsante Stop Thread, che interromperà il thread.
void CMFCMultithreadingDlg::OnBnClickedButtonStop() {
// TODO: Add your control notification handler code here
stopNow = TRUE;
KillTimer(1234);
m_ctrlStatus.SetWindowText(L"Stopped");
}
Step 9 - Ecco il file sorgente completo.
// 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 - Quando il codice sopra è stato compilato ed eseguito, vedrai il seguente output.
Step 11 - Ora fai clic sul pulsante Avvia thread.
Step 12- Fare clic sul pulsante Interrompi thread. Fermerà il filo.