MFC中多线程的应用

    技术2022-05-11  113

    MFC中多线程的应用

    -------------------------------------------------------------------------------

      我试着用自已的话来表述线程的概念,还有很短时间里编的一个小示例程序(不知恰当不?,也不知能说得清不..),见笑了.

      线程其实和标准的windows主程序(WinMain)没啥两样...主程序其实是一个特殊的线程,称为主线程而已,其实你完全可以把线程想象成和winmain一起**同时运行**,但是** 可以相互访问(即在一个地址空间) **的一些小的WinMain程序.它和主线程一样,里面可以创建窗口,获取消息,等等..

       由于线程们在一个地址空间且同时运行,所以会造成一些麻烦。因为我们编程都要用别人的函数库,而他们的函数库里面往往会有很多静态或全局的状态或中间变量,有着很复杂的相互依赖关系,如果执行某个功能不串行化(所谓串行化,也就是只能等一个功能调用返回后,另一个线程才能调用,不可以同时调用),就会造成大乱.这对线程来说,有术语称同步,windows为我们提供了很多同步的方法,MFC也提供了一些同步核心对象的类封装.对于某个功能调用库来说,叫线程安全.比如MFC的类库并不是线程安全的.

       现在我举个刚刚自编的例子来简单说明这些概念。下面的一个对话框应用是多线程的.演示两个小动画:

      (1)第一个动画由主线程的Timer来驱动,第二个动画由主线所创建的工作线程来驱动.分别显示在不同的位置.之所以我要加入Timer,也是为了形成线程驱动和timer驱动的对照,这是动画的两种驱动方式(还有在idle中驱动的)。

      (2)这两个动画永远是不同的.也就是比如:一个是变哭,一个就会变笑,等那个变笑了,这个就变哭.动画图片来自于OICQ中的Face目录下,一般同样的头像会oicq会带三个图片(*-1.bmp,*-2.bmp,*-3.bmp),*-2.bmp是变灰的图片,我就取了1和3的图片来作动画.

       这个程序的几个关键要注意的:

      (1)主线程用PostThreadMessage和工作线程通信.工作线程用PeekMessage来取回消息。为了简单起见,我只用了一个WM_QUIT的消息来指示工作线程退出.

      (2)主线程和工作线程同时调用了一个DisplayFace函数来进行动画显示.为了让两个动画一哭一笑做到不同,采用了CCriticalSection来进行同步.

      示例如下:

      (1)先用appwizards生成一个MFC的Dialog应用模板,假定对话框类为CTest01Dlg。

      (2)再添入两个oicq的bmp文件到资源中去

      (3)添加一个按钮(button)到对话框上.用作启动、停止动画的button

      (4)用ClassWizard为button/onclick及dlg/ontimer生成事件响应函数,

      (5)用Resource Symbol加入一个标识定义IDC_TIMER1

      (6)在ClassView中为CTest01Dlg加入以下成员变量和成员函数

        CriticalSection ccs;

        CBitmap bm[2];

        CWinThread* pMyThread;

        static UINT MyThreadProc( LPVOID pParam);

        void DisplayFace(CPoint r);

        实现文件中加入相应代码(见下面)

      (7)stdafx.h中加入#include

      源代码如下,凡是我新加的代码周围都有注释包围,其它是ClassWizards自动写的:

      // stdafx.h : include file for standard system include files,

      // or project specific include 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 once

      #endif // _MSC_VER > 1000

      #define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers

      #include // MFC core and standard components

      #include // MFC extensions

      #include // MFC support for Internet Explorer 4 Common Controls

      file://加入头引用主要是CCriticalSection对象的定义.

      #include

      file://加入结束

      #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 immediately before the previous 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 once

      #endif // _MSC_VER > 1000

      /

      // CTest01Dlg dialog

      class CTest01Dlg : public CDialog

      {

       // Construction

       public:

       file://加入

       CBitmap bm[2];

       CCriticalSection ccs;

       CWinThread* pMyThread;

       static UINT MyThreadProc( LPVOID pParam);

       void DisplayFace(CPoint r);

       CTest01Dlg(CWnd* pParent = NULL); // standard constructor

       file://加入结束

       // 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 immediately before the previous 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://加入

        pMyThread =NULL;

        file://加入结束

       }

      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::OnInitDialog()

       {

        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 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

        file://加入

        bm[0].LoadBitmap (IDB_BITMAP1);

        bm[1].LoadBitmap (IDB_BITMAP3);

        file://加入结束

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

       }

       void CTest01Dlg::OnSysCommand(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 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

        {

         CDialog::OnPaint();

        }

       }

       HCURSOR CTest01Dlg::OnQueryDragIcon()

        {

         return (HCURSOR) m_hIcon;

         }

        file://加入

        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("停止"):_T("启动")));

        }

        void CTest01Dlg::OnTimer(UINT nIDEvent)

        {

         if (nIDEvent==IDC_TIMER1)

          DisplayFace(CPoint(10,10));

          CDialog::OnTimer(nIDEvent);

         }

        void CTest01Dlg::DisplayFace(CPoint p)

         {

          static int i=0;

          ccs.Lock ();

          BITMAP bmo;

          bm[i].GetObject (sizeof(bmo),&bmo);

          CClientDC dc(this);

          CDC bmpDC;

          bmpDC.CreateCompatibleDC (&dc);

          bmpDC.SelectObject (&bm[i]);

          dc.BitBlt (p.x ,p.y ,bmo.bmWidth,bmo.bmHeight,&bmpDC,0,0,SRCCOPY);

          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://加入结束

     

     


    最新回复(0)