Multiple threads in MFC
-------------------------------------------------- -----------------------------
I tried to express the concept of threads with self, there is a small sample program compiled in a short time (I don't know if it is right, I don't know if I can say it ..), I laugh.
Thread actually and the standard Windows main program (WinMain) is not a two ... The main program is actually a special thread, called the main thread, in fact, you can do the thread to be integrated with WinMain. ** But ** can access some small Winmain programs (ie in an address space) **. Like the main thread, you can create a window, get a message, and more ..
Since the threads are running at an address space, it will cause some trouble. Because we have programmed the library of others, and their library often has a lot of static or global status or intermediate variables, there is a complex mutual dependency, if a function is not serialized (so-called string It is to train, that is, only one function call is returned, another thread can call, can not call at the same time, will cause chaos. This is a thread, and the term is synchronized. Windows provides us with a lot of synchronization. Methods, MFC also provides some classification of synchronous core objects. For a feature call library, call thread security. For example, the MFC class library is not a thread.
Now I will give an example of just a self-organizing example. One of the following dialog applications is multithreaded. Demo two small animations:
(1) The first animation is driven by the main thread Timer. The second animation is driven by the working thread created by the main line. Displayed in different locations, and I want to join Timer, and to form thread drivers and Timer Drive control, this is the two driving methods of animation (also driven in idle).
(2) These two animations will always be different. This is, for example, one is crying, one will smile, wait for that smile, this is crying. The animation picture comes from the Face directory in OICQ, general The same avatar will take three pictures (* -1.bmp, * - 2.bmp, * - 3.bmp), * - 2.BMP is a gray picture, I will take pictures of 1 and 3 To make animations.
Several key to this program pay attention to:
(1) The main thread uses PostthreadMessage and work thread communication. Work thread Use PeekMessage to retrieve the message. For simplicity, I only use a WM_QUIT message to indicate the work thread exits.
(2) The main thread and the working thread simultaneously call a DisplayFace function to make an animation display. In order to make two animation crying and smile, using ccriticalsection to synchronize.
Examples are as follows:
(1) First Generate an MFC Dialog Application Template with AppWizards, assume that the dialog box is CTEST01DLG.
(2) Add two OICQ's BMP files to resources.
(3) Add a button (Button) to the dialog box. Used as startup, stop the animation of Button
(4) Generate event response functions with ClassWizard to Button / OnClick and DLG / ONTIMER,
(5) Add a logo definition IDC_TIMER1 with Resource Symbol
(6) Add the following member variables and member functions to CTEST01DLG in ClassView.
Criticalsection CCS;
CBITMAP BM [2];
CWINTHREAD * PMYTHREAD;
Static uint mythreadproc (lpvoid pparam);
Void DisplayFace (CPOINT R);
Add corresponding code in the implementation file (see below)
(7) Add #include in stdafx.h
The source code is as follows, and every surprise surrounded by my new code is surrounded by ClassWizards.
// stdafx.h: include File for Standard System Include Files,
// or project specificin files That Are Used Frequently, But // Are Changed Infrequently
File: //
#if! defined (afX_STDAFX_H__5B92DAA8_FE27_4702_8037_A2538343E69D__included_)
#define AFX_STDAFX_H__5B92DAA8_FE27_4702_8037_A2538343E69D__included_
#iF _MSC_VER> 1000
#pragma overce
#ENDIF / / 100 m _ _
#define vc_extralean // Exclude Rarely-usest Stuff from Windows Headers
#include // MFC Core and Standard Components
#include // mfc extensions
#include // MFC Support for Internet Explorer 4 Common Controls
File: // The joining header is mainly defined by the CcriticalSection object.
#include
File: // Add to end
#ifndef _AFX_NO_AFXCMN_SUPPORT
#include // MFC Support for Windows Common Controls
#ENDIF / / _AFX_NO_AFXCMN_SUPPORT
File: // {{{AFX_INSERT_LOCATION}}}
// Microsoft Visual C Will Insert Additional Declarations Immediate Line.
#ENDIF /! Defined (AFX_STDAFX_H__5B92DAA8_FE27_4702_8037_A2538343E69D__included_)
// Test01dlg.h: Header File
File: //
#if! defined (AFX_TEST01DLG_H__F3780E23_CCFC_468C_A262_50FFF1D991BC__INCLUDED_)
#define AFX_TEST01DLG_H__F3780E23_CCFC_468C_A262_50FFF1D991BC__INCLUDED_
#iF _MSC_VER> 1000
#pragma overce
#ENDIF / / 100 m _ _
/
// ctest01dlg dialog
Class ctest01dlg: public cdialog
{
// construction
PUBLIC:
File: // Join
CBITMAP BM [2];
CcriticalSECTION CCS;
CWINTHREAD * PMYTHREAD;
Static uint mythreadproc (lpvoid pparam);
Void DisplayFace (CPOINT R);
CTEST01DLG (CWND * PParent = null); // Standard Constructionor
File: // Add to end
// Dialog Data
FILE: / / {{AFX_DATA (CTEST01DLG)
ENUM {IDD = IDD_TEST01_DIALOG};
// Note: The Classwizard Will Add Data MEMBERS Here
File: //}} AFX_DATA
// ClassWizard Generated Virtual Function Overrides
File: // {{AFX_VIRTUAL (CTEST01DLG)
protected:
Virtual Void DodataExchange (CDataExchange * PDX); // DDX / DDV Support
File: //}} AFX_VIRTUAL
// Implementation
protected:
Hicon M_Hicon;
// generated message map functions
File: // {{{AFX_MSG (CTEST01DLG)
Virtual Bool OnInitdialog ();
AFX_MSG Void OnSysCommand (Uint Nid, LParam Lparam);
AFX_MSG void onpaint ();
AFX_MSG HCURSOR ONQUERYDRAGICON ();
AFX_MSG void onbutton1 ();
AFX_MSG Void Ontimer (uint nidEvent);
File: //}} AFX_MSG
Declare_message_map ()
}
File: // {{{AFX_INSERT_LOCATION}}}
// Microsoft Visual C Will Insert Additional Declarations Immediate Line.
#endif //! defined (AFX_TEST01DLG_H__F3780E23_CCFC_468C_A262_50FFF1D991BC__INCLUDED_)
// TEST01DLG.CPP: Implementation File
File: //
#include "stdafx.h"
#include "test01.h"
#include "test01dlg.h"
#ifdef _Debug
#define new debug_new
#undef this_file
Static char this_file [] = __file__;
#ENDIF
/
// Caboutdlg Dialog Used for App About
Class Caboutdlg: Public CDIALOG
{
PUBLIC:
Caboutdlg ();
// Dialog Data
File: // {{AFX_DATA (Caboutdlg)
Enum {IDD = IDD_ABOUTBOX};
File: //}} AFX_DATA
// ClassWizard Generated Virtual Function Overrides
File: // {{{AFX_VIRTUAL (Caboutdlg)
protected:
Virtual Void DodataExchange (CDataExchange * PDX); // DDX / DDV Support
File: //}} AFX_VIRTUAL
// Implementation
protected:
File: // {{{AFX_MSG (Caboutdlg)
File: //}} AFX_MSG
Declare_message_map ()
}
Caboutdlg :: Caboutdlg (): cdialog (Caboutdlg :: IDD)
{
File: // {{AFX_DATA_INIT (Caboutdlg)
File: //}} AFX_DATA_INIT
}
Void Caboutdlg :: DODATAEXCHANGE (CDataExchange * PDX)
{
CDIALOG :: DODATAEXCHANGE (PDX);
FILE: / / {{{AFX_DATA_MAP (Caboutdlg)
File: //}} AFX_DATA_MAP
}
Begin_MESSAGE_MAP (Caboutdlg, CDIALOG)
File: // {{AFX_MSG_MAP (Caboutdlg) // No Message Handlers
File: //}} AFX_MSG_MAP
END_MESSAGE_MAP ()
/
// ctest01dlg dialog
CTEST01DLG :: CTEST01DLG (CWND * PParent / * = NULL * /)
: Cdialog (ctest01dlg :: IDd, pparent)
{
File: // {{AFX_DATA_INIT (CTEST01DLG)
// Note: The classwizard will add member initialization here
File: //}} AFX_DATA_INIT
// Note That Loadicon Does Not Require a Subsequent Destroyicon in Win32
m_hicon = AFXGetApp () -> loadicon (iDR_mainframe);
File: // Join
PMYTHREAD = NULL;
File: // Add to end
}
Void ctest01dlg :: DODATAEXCHANGE (CDataExchange * PDX)
{
CDIALOG :: DODATAEXCHANGE (PDX);
FILE: / / {{{AFX_DATA_MAP (CTEST01DLG)
// Note: The Classwizard Will Add Ddx and DDV Calls Here
File: //}} AFX_DATA_MAP
}
Begin_MESSAGE_MAP (CTEST01DLG, CDIALOG)
File: // {{AFX_MSG_MAP (CTEST01DLG)
ON_WM_SYSCOMMAND ()
ON_WM_PAINT ()
ON_WM_QUERYDRAGICON ()
ON_BN_CLICKED (IDC_Button1, Onbutton1)
ON_WM_TIMER ()
File: //}} AFX_MSG_MAP
END_MESSAGE_MAP ()
/
// ctest01dlg Message Handlers
BOOL CTEST01DLG :: OnItDialog ()
{
CDIALOG :: OnInitdialog ();
// Add "About ..." Menu Item to System Menu.
// IDM_AboutBox Must Be in The System Command Range.
Assert (IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
Assert (IDM_AboutBox <0xf000);
CMenu * psysmenu = getSystemMenu (false);
IF (psysmenu! = NULL)
{
CSTRING STRABOUTMENU;
STRABOUTMENU.LOADSTRING (IDS_ABOUTBOX);
IF (! straboutmenu.isempty ())
{
Psysmenu-> appendmenu (mf_separator);
Psysmenu-> appendmenu (mf_string, idm_aboutbox, straboutmenu);
}
}
// set the icon for this dialog. The framework does this AutomaticL
// 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
File: // Join
BM [0] .loadBitmap (idb_bitmap1);
BM [1] .loadBitmap (IDB_bitmap3);
File: // Add to end
Return True; // Return True UnsS you set the focus to a control
}
Void ctest01dlg :: oversyscommand (uint nid, lparam lparam)
{
IF ((NID & 0xFFF0) == IDM_ABOUTBOX)
{
Caboutdlg dlgabout;
DLGAbout.domodal ();
}
Else
{
CDIALOG :: OnSysCommand (NID, LPARAM);
}
}
Void ctest01dlg :: onpaint ()
{
IF (Isiconic ())
{
CPAINTDC DC (this); // Device Context for Painting
SendMessage (WM_ICONERASEBKGND, (WPARAM) dc.getsafehdc (), 0);
// Center icon in Client Rectangle
INT CXCION = 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
{
CDIALOG :: onpaint ();
}
}
Hcursor ctest01dlg :: ONQUERYDRAGICON ()
{
Return (hcursor) m_hicon;
}
File: // Join
Void ctest01dlg :: onbutton1 ()
{
Static bool bstarted = false;
IF (! bstarted) {
Settimer (IDC_TIMER1, 500, NULL);
PMYTHREAD = AFXBEGINTHREAD (MythreadProc, this);
} else {
IF (PMYTHREAD) {
PMYTHREAD-> PostthreadMessage (wm_quit, 0,0);
:: WaitforsingleObject (PMYTHREAD-> M_HTHREAD, INFINITE);
PMYTHREAD = NULL;
}
KillTimer (IDC_TIMER1);
}
Bstarted =! bstarted;
((Cbutton *) getdlgitem (idc_button1)) -> setWindowText ((bstarted? _T ("stop"): _ t ("start")));
}
Void ctest01dlg :: ONTIMER (uint nidevent)
{
IF (nidevent == idc_timer1)
DisplayFace (CPOINT (10, 10));
CDIALOG :: ONTIMER (Nidevent);
}
Void ctest01dlg :: DisplayFace (cpoint p)
{
Static I = 0;
CCS.LOCK ();
Bitmap bmo;
BM [I] .GetObject (Sizeof (BMO), & BMO; CClientDC DC (this);
CDC BMPDC;
BMPDC.CREATECOMPALEDC (& DC);
BMPDC.SELECTOBJECT (& BM [i]);
DC.Bitblt (P.x, P.Y, BMo.bmwidth, Bmo.bmheight, & BMPDC, 0, 0, SRCCPY);
i ;
IF (i == sizeof (bm) / sizeof (BM [0])) i = 0;
CCS.unlock ();
}
Uint ctest01dlg :: MythreadProc (lpvoid pparam)
{
CTEST01DLG * ME = (CTEST01DLG *) PPARAM;
MSG msg;
While (! PeekMessage (& MSG, NULL, 0, 0, PM_NOREMOVE) {
ME-> DisplayFace (CPOINT (100, 10));
:: Sleep (200);
}
Return 0;
}
File: // Add to end