MFC多執行緒計算圓周率介面化演示
阿新 • • 發佈:2018-12-10
學期末老師讓設計一個多執行緒無限計算圓周率的圖形化演示內容。我採取MFC進行設計的。
其中的一個執行緒用來計算pi,採用的是之前傳的一段神奇的計算圓周率的程式碼,它採用每次計算4位的方法,很適合這個練習的可以進行演示的要求。關於這個演算法的理解我是基於以下連結點選開啟連結,博主說得挺清楚。另一個執行緒是用來進行輸出演示的,由此實現了多執行緒。
原始碼如下。由於在設計的時候現用現學的MFC(嘛,我現在並不是IT專業的學生嘛....看下學期初了),所以建議沒有學過的同學呢先跟著做幾個MFC的小例子,基本就可以入門MFC理解這些程式碼每一部分的意義了。不要害怕那些大段大段的模板程式碼....
// multithreadingDlg.cpp : 實現檔案 // #include "stdafx.h" #include "multithreading.h" #include "multithreadingDlg.h" #include "afxdialogex.h" #include "resource.h" #include <conio.h> #include <cmath> #ifdef _DEBUG #define new DEBUG_NEW #endif // 用於應用程式“關於”選單項的 CAboutDlg 對話方塊 class CAboutDlg : public CDialogEx { public: CAboutDlg(); // 對話方塊資料 enum { IDD = IDD_ABOUTBOX }; protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支援 // 實現 protected: DECLARE_MESSAGE_MAP() }; CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD) { } void CAboutDlg::DoDataExchange(CDataExchange* pDX) { CDialogEx::DoDataExchange(pDX); } BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx) END_MESSAGE_MAP() // CmultithreadingDlg 對話方塊 CmultithreadingDlg::CmultithreadingDlg(CWnd* pParent /*=NULL*/) : CDialogEx(CmultithreadingDlg::IDD, pParent) , m_prec(0),i(0) { m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); } void CmultithreadingDlg::DoDataExchange(CDataExchange* pDX) { CDialogEx::DoDataExchange(pDX); DDX_Text(pDX, IDC_EDIT1, m_prec); DDX_Control(pDX, IDC_EDIT2, m_result); } BEGIN_MESSAGE_MAP(CmultithreadingDlg, CDialogEx) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_BN_CLICKED(IDC_BUTTON1, &CmultithreadingDlg::OnBnClickedButton1) ON_BN_CLICKED(IDC_BUTTON2, &CmultithreadingDlg::OnBnClickedButton2) ON_BN_CLICKED(IDC_BUTTON3, &CmultithreadingDlg::OnBnClickedButton3) ON_BN_CLICKED(IDCANCEL, &CmultithreadingDlg::OnBnClickedCancel) ON_EN_CHANGE(IDC_EDIT1, &CmultithreadingDlg::OnEnChangeEdit1) ON_EN_CHANGE(IDC_EDIT2, &CmultithreadingDlg::OnEnChangeEdit2) ON_MESSAGE(WM_MY_PIMESSAGE, &CmultithreadingDlg::OnMyPimessage) END_MESSAGE_MAP() // CmultithreadingDlg 訊息處理程式 BOOL CmultithreadingDlg::OnInitDialog() { CDialogEx::OnInitDialog(); // 將“關於...”選單項新增到系統選單中。 // IDM_ABOUTBOX 必須在系統命令範圍內。 ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); ASSERT(IDM_ABOUTBOX < 0xF000); CMenu* pSysMenu = GetSystemMenu(FALSE); if (pSysMenu != NULL) { BOOL bNameValid; CString strAboutMenu; bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX); ASSERT(bNameValid); if (!strAboutMenu.IsEmpty()) { pSysMenu->AppendMenu(MF_SEPARATOR); pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); } } // 設定此對話方塊的圖示。當應用程式主視窗不是對話方塊時,框架將自動 // 執行此操作 SetIcon(m_hIcon, TRUE); // 設定大圖示 SetIcon(m_hIcon, FALSE); // 設定小圖示 // TODO: 在此新增額外的初始化程式碼 return TRUE; // 除非將焦點設定到控制元件,否則返回 TRUE } void CmultithreadingDlg::OnSysCommand(UINT nID, LPARAM lParam) { if ((nID & 0xFFF0) == IDM_ABOUTBOX) { CAboutDlg dlgAbout; dlgAbout.DoModal(); } else { CDialogEx::OnSysCommand(nID, lParam); } } // 如果向對話方塊新增最小化按鈕,則需要下面的程式碼 // 來繪製該圖示。對於使用文件/檢視模型的 MFC 應用程式, // 這將由框架自動完成。 void CmultithreadingDlg::OnPaint() { if (IsIconic()) { CPaintDC dc(this); // 用於繪製的裝置上下文 SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0); // 使圖示在工作區矩形中居中 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; // 繪製圖標 dc.DrawIcon(x, y, m_hIcon); } else { CDialogEx::OnPaint(); } } //當用戶拖動最小化視窗時系統呼叫此函式取得游標 //顯示。 HCURSOR CmultithreadingDlg::OnQueryDragIcon() { return static_cast<HCURSOR>(m_hIcon); } void CmultithreadingDlg::OnBnClickedButton2() { // TODO: 在此新增控制元件通知處理程式程式碼 CString str; if(GetDlgItem(IDC_BUTTON2)->GetWindowText(str), str == "Pause"){ SuspendThread(hThread); GetDlgItem(IDC_BUTTON2)->SetWindowTextW(_T("Continue")); } else if(GetDlgItem(IDC_BUTTON2)->GetWindowText(str), str == "Continue"){ ResumeThread(hThread); GetDlgItem(IDC_BUTTON2)->SetWindowText(_T("Pause")); } } UINT Thread(CmultithreadingDlg *Dlg) { long a = 10000, b, c = 2800, d, e = 0, f[2801]; for(b = 0; b < c; b ++) f[b] = a / 5; while(1){ while(c > 0){ d = 0; for(b = c; b > 0; b --){ d = d*b + f[b]*a; f[b] = d %(2*b - 1); d /= 2*b - 1; } Dlg->p_result0 = e + d/a; Dlg->SendMessage(WM_MY_PIMESSAGE, 0); e = d % a; c -= 14; } } return 0; } void CmultithreadingDlg::OnBnClickedButton1() { // TODO: 在此新增控制元件通知處理程式程式碼 CString str; UpdateData(TRUE); GetDlgItem(IDC_BUTTON1)->EnableWindow(FALSE); GetDlgItem(IDC_BUTTON3)->EnableWindow(TRUE); GetDlgItem(IDC_BUTTON2)->EnableWindow(TRUE); if(GetDlgItem(IDC_BUTTON2)->GetWindowText(str), str == "Continue"){ GetDlgItem(IDC_BUTTON2)->SetWindowText(_T("Pause")); } hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Thread, this, CREATE_SUSPENDED, ThreadID); ResumeThread(hThread); } void CmultithreadingDlg::OnBnClickedButton3() { // TODO: 在此新增控制元件通知處理程式程式碼 TerminateThread(hThread, NULL); m_result.SetWindowTextW(_T("")); GetDlgItem(IDC_BUTTON1)->EnableWindow(FALSE); GetDlgItem(IDC_BUTTON2)->EnableWindow(FALSE); GetDlgItem(IDC_BUTTON3)->EnableWindow(FALSE); } void CmultithreadingDlg::OnBnClickedCancel() { // TODO: 在此新增控制元件通知處理程式程式碼 GetDlgItem(IDC_BUTTON1)->EnableWindow(TRUE); GetDlgItem(IDC_BUTTON2)->EnableWindow(FALSE); TerminateThread(hThread, NULL); CDialogEx::OnCancel(); } void CmultithreadingDlg::OnEnChangeEdit1() { // TODO: 如果該控制元件是 RICHEDIT 控制元件,它將不 // 傳送此通知,除非重寫 CDialogEx::OnInitDialog() // 函式並呼叫 CRichEditCtrl().SetEventMask(), // 同時將 ENM_CHANGE 標誌“或”運算到掩碼中。 //#1015 // TODO: 在此新增控制元件通知處理程式程式碼 UpdateData(TRUE); } void CmultithreadingDlg::OnEnChangeEdit2() { // TODO: 如果該控制元件是 RICHEDIT 控制元件,它將不 // 傳送此通知,除非重寫 CDialogEx::OnInitDialog() // 函式並呼叫 CRichEditCtrl().SetEventMask(), // 同時將 ENM_CHANGE 標誌“或”運算到掩碼中。 //#1015 // TODO: 在此新增控制元件通知處理程式程式碼 } afx_msg LRESULT CmultithreadingDlg::OnMyPimessage(WPARAM wParam, LPARAM lParam) { // TODO: 處理使用者自定義訊息 UpdateData(TRUE); CString t; int pi_[4]; Sleep(50); int j = 0; j = i % 4; switch(j){ case 0: { pi_[0] = p_result0 / 1000; t.Format(_T("%1d"), pi_[0]); m_result.ReplaceSel((LPCTSTR)t, 0); if(i ++ == m_prec - 1){ TerminateThread(hThread, NULL); break; } if(i == 1) m_result.ReplaceSel((LPCTSTR)".", 0); } case 1: { pi_[1] = p_result0 % 1000/100; t.Format(_T("%1d"), pi_[1]); Sleep(50); m_result.ReplaceSel((LPCTSTR)t, 0); if(i ++ == m_prec - 1){ TerminateThread(hThread, NULL); break; } } case 2: { pi_[2] = p_result0 /10 %10; t.Format(_T("%1d"), pi_[2]); Sleep(50); m_result.ReplaceSel((LPCTSTR)t, 0); if(i ++ == m_prec - 1){ TerminateThread(hThread, NULL); break; } } case 3: { pi_[3] = p_result0 %10; t.Format(_T("%1d"), pi_[3]); Sleep(50); m_result.ReplaceSel((LPCTSTR)t, 0); if(i ++ == m_prec - 1){ TerminateThread(hThread, NULL); break; } } } return 0; }