1. 程式人生 > >MFC多執行緒計算圓周率介面化演示

MFC多執行緒計算圓周率介面化演示

學期末老師讓設計一個多執行緒無限計算圓周率的圖形化演示內容。我採取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;
}