C++ MFC 中使用多线程操作实例

来源:互联网 发布:c语言鸡兔同笼代码 编辑:程序博客网 时间:2024/06/03 22:42



多线程实例(一)

此实例为简单的多线程,实现动态显示时间

1、.h中:

protected:
 HICON m_hIcon;
 HANDLE hThread;//线程句柄
 DWORD threadID;//线程Id
 // Generated message map functions
 //{{AFX_MSG(CMthread1Dlg)
 virtual BOOL OnInitDialog();
 afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
 afx_msg void OnPaint();
 afx_msg HCURSOR OnQueryDragIcon();
 afx_msg void OnStart();
 afx_msg void OnStop();

2、.cpp中:

volatile BOOL m_bRun;//代表线程是否正常运行

void ThreadProc()
{
 CTime time;
 CString strTime;
 m_bRun = TRUE;

 while(m_bRun)
 {
  time = CTime::GetCurrentTime();
  strTime = time.Format("%H:%M:%S");

  ::SetDlgItemText(AfxGetMainWnd()->m_hWnd,IDC_TIME,strTime);
  Sleep(1000);
 }
}
class CAboutDlg : public CDialog
{
public:
 CAboutDlg();

// Dialog Data
 //{{AFX_DATA(CAboutDlg)
 enum { IDD = IDD_ABOUTBOX };
 //}}AFX_DATA

 // ClassWizard generated virtual function overrides
 //{{AFX_VIRTUAL(CAboutDlg)
 protected:
 virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
 //}}AFX_VIRTUAL

// Implementation
protected:
 //{{AFX_MSG(CAboutDlg)
 //}}AFX_MSG
 DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
 //{{AFX_DATA_INIT(CAboutDlg)
 //}}AFX_DATA_INIT
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
 CDialog::DoDataExchange(pDX);
 //{{AFX_DATA_MAP(CAboutDlg)
 //}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
 //{{AFX_MSG_MAP(CAboutDlg)
  // No message handlers
 //}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CMthread1Dlg dialog

CMthread1Dlg::CMthread1Dlg(CWnd* pParent /*=NULL*/)
 : CDialog(CMthread1Dlg::IDD, pParent)
{
 //{{AFX_DATA_INIT(CMthread1Dlg)
  // NOTE: the ClassWizard will add member initialization here
 //}}AFX_DATA_INIT
 // Note that LoadIcon does not require a subsequent DestroyIcon in Win32
 m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CMthread1Dlg::DoDataExchange(CDataExchange* pDX)
{
 CDialog::DoDataExchange(pDX);
 //{{AFX_DATA_MAP(CMthread1Dlg)
  // NOTE: the ClassWizard will add DDX and DDV calls here
 //}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CMthread1Dlg, CDialog)
 //{{AFX_MSG_MAP(CMthread1Dlg)
 ON_WM_SYSCOMMAND()
 ON_WM_PAINT()
 ON_WM_QUERYDRAGICON()
 ON_BN_CLICKED(IDC_START, OnStart)
 ON_BN_CLICKED(IDC_STOP, OnStop)
 //}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CMthread1Dlg message handlers

BOOL CMthread1Dlg::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
 
 return TRUE;  // return TRUE  unless you set the focus to a control
}

void CMthread1Dlg::OnSysCommand(UINT nID, LPARAM lParam)
{
 if ((nID & 0xFFF0) == IDM_ABOUTBOX)
 {
  CAboutDlg dlgAbout;
  dlgAbout.DoModal();
 }
 else
 {
  CDialog::OnSysCommand(nID, lParam);
 }
}

// 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 CMthread1Dlg::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();
 }
}

// The system calls this to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CMthread1Dlg::OnQueryDragIcon()
{
 return (HCURSOR) m_hIcon;
}

void CMthread1Dlg::OnStart()
{
 // TODO: Add your control notification handler code here
 hThread = CreateThread(
        NULL,          // SD
        0,          // initial stack size
        (LPTHREAD_START_ROUTINE)ThreadProc,    // thread function
        NULL,          // thread argument
        0,          // creation option
        &threadID         // thread identifier
      );
 GetDlgItem(IDC_START)->EnableWindow(FALSE);
 GetDlgItem(IDC_STOP)->EnableWindow(TRUE);

void CMthread1Dlg::OnStop()
{
 // TODO: Add your control notification handler code here
 m_bRun = FALSE;
 GetDlgItem(IDC_START)->EnableWindow(TRUE);
 GetDlgItem(IDC_STOP)->EnableWindow(FALSE);
}

多线程实例(二)

此实例演示采用CreateThread函数在主线程中创建一个线程,并且向创建的线程中传递一个参数。

线程函数:

void ThreadProc(int count)  

{  

    for (int i=0; i < count; i++)  

    {  

        Beep(2000,50);  

        Sleep(200);  

  }  

}  

主线程函数:

void CMthread2Dlg::OnStart()   


{  

 // TODO: Add your control notification handler code here  

    UpdateData(TRUE);//从控件中检索数据  

    int count = m_count;  

    hThread = CreateThread(NULL,  

                           0,  

                           (LPTHREAD_START_ROUTINE)ThreadProc,  

                           (VOID *)count,  

                           0,  

                           &threadID  

                           );  

    GetDlgItem(IDC_START)->EnableWindow(FALSE);  

    WaitForSingleObject(hThread,INFINITE); //当线程挂起时,为有信号状态  

   GetDlgItem(IDC_START)->EnableWindow(TRUE);  

}  

注:变量m_count和控件IDC_COUNT做了关联。
函数说明:

     BOOL UpdateData( BOOL bSaveAndValidate = TRUE );

    MFC中的窗口函数,在对话框中,当建立控件和变量之间的关联关系后,修改变量值,希望对话框更新显示,则bSaveAndValidate=FALSE,即调用UpdateData(FALSE);当需要获取对话框中控件输入的值时,则bSaveAndValidate=TRUE,即调用UpdateData(TRUE)。

注意:

主线程中,调用了WaitForSingleObject函数,此函数的作用是监视hHandle的状态,当监视的句柄为有信号状态时,即此对象为空闲状态时,此函数返回,才能执行其后的代码。

在此处,用WaitForSingleObject作用:

由于c++主程序终止,同时它创建的相应的线程也会终止,它不管子线程是否执行完成,因此,上文中如果不调用WaitForSingleObject函数,则子线程ThreadProc可能没有执行完或者没执行。

多线程实例(三)

此实例演示多线程中,主线程向子线程传递一个结构体。

在头文件中,声明线程函数及结构体:

UINT ThreadProc(LPVOID lpParam);  

struct threadInfo  

{  

    UINT nMilliSecond;  

    CProgressCtrl *pctrProcess;  

};  


子线程定义函数:

threadInfo myInfo;  

UINT ThreadProc(LPVOID lpParam)  

{  

    threadInfo *pInfo = (threadInfo *)lpParam;  

    for (int i=0; i<100; i++)  

    {  

        int iTmp = pInfo->nMilliSecond;  

        pInfo->pctrProcess->SetPos(i);  

        Sleep(iTmp);  

    }  

    return 0;  

}  

主线程调用子线程函数:

void CMthread3Dlg::OnStart()   


{  

    // TODO: Add your control notification handler code here  

        UpdateData();//默认为TRUE  

        myInfo.nMilliSecond = m_nMillSecond;  

        myInfo.pctrProcess = &m_ctrProcess;  

        hThread = CreateThread(NULL,  

                                0,  

                                (LPTHREAD_START_ROUTINE)ThreadProc,  

                               &myInfo,  

                                0,  

                                &threadID  

                                );  

        /*GetDlgItem(IDC_START)->EnableWindow(FALSE); 

        WaitForSingleObject(hThread,INFINITE); 

        GetDlgItem(IDC_START)->EnableWindow(TRUE);*/  

    }  

    注意注释的部分,如果调用WaitForSingleObject函数,此程序会出现死锁。因为对话框中有个进度条,子线程中设置进度条的进度,但是进度条的刷新需要主线程来完成,当主线程调用WaitForSingleObject函数挂起后,子线程设置正在设置进度条,一直等待主线程将刷新消息出来完毕返回才检测通知事件。这样两个线程一直处于相互等待,出现死锁。




















    
    0 0
    原创粉丝点击