1. 程式人生 > >C++實現一個簡單的雙執行緒MVC框架

C++實現一個簡單的雙執行緒MVC框架

        花了一上午,初步實現一個簡單的MVC框架,原理如下:

兩個執行緒一個控制執行緒(處理業務邏輯的工作執行緒),一個檢視使用執行緒(往往應該就是UI執行緒)。所有檢視操作應該在UI執行緒中操作,業務邏輯和對model的修改在工作執行緒中做。

實現控制器類PrintController 主要功能是處理使用者輸入資料,然後更新到模型中;是否及時通知介面也在這裡通過model->Notify()來控制——雖然可以在修改每一個model的資料時通知介面,但有的時候更新多個數據後一次通知介面會顯得效率更高。

實現檢視類PrintView 除了繼承ViewBase基類外,還是Observer和ThreadBase的子類;對於Observer,是為了設定在Model當更新時候通知的觀察者介面;對於ThreadBase是為了在檢視中建立新執行緒來處理檢視功能。PrintTask是任務結構,我認為這裡沒有設計得合理,接下來嘗試不同的方案優化。這裡的非同步執行緒任務提交是一個可以進一步很好優化的地方,比如使用C++11的中std::bind來繫結任務然後遞交,目前我使用的是vs2008,不支援C++11的這個特性,我打算接下來自己實現std::bind的功能,然後應用進來。

實現模型類PrintModel 這個類的功能相對比較清楚明瞭,就是提供註冊觀察者的介面(view),實現資料的讀取與更改。我使用友元嘗試不讓檢視部分更改資料,只讓控制器可以修改資料。

原理說到這裡,直接上程式碼:

MVCDemo.cpp

#include "stdafx.h"
#include "PrintController.h"
#include "PrintModel.h"
#include "PrintView.h"
#include <iostream>

using std::wcin;
using std::endl;

int _tmain(int argc, _TCHAR* argv[])
{

	
	PrintModel model;
	PrintController controller(&model);
	PrintView view(&model);
	controller.Register(&model,&view);

	view.Run();
	std::wstring str;

	while (1)
	{
		wcin>>str;
		controller.HandleUserInput(&str);
	}

	return 0;
}

PrintController.cpp
#include "PrintController.h"
#include "PrintModel.h"

PrintController::PrintController(PrintModel* model)
:model_(model)
{
}

PrintController::~PrintController(void)
{
}

void PrintController::Register(ModelBase* model, Observer* observer)
{
	model->Attach(observer);
	return;
}


void PrintController::HandleUserInput(const std::wstring* inputstr)
{
	model_->SetPrintString(inputstr);
	model_->Notify();
	return;
}

PrintModel.cpp
#include "PrintModel.h"
#include "Observer.h"

PrintModel::PrintModel(void)
{
}

PrintModel::~PrintModel(void)
{
}

void PrintModel::Attach(Observer * observer)
{
	observerlist_.push_front(observer);
}

void PrintModel::Detach(Observer * observer)
{
	observerlist_.remove(observer);
}

void PrintModel::Notify()
{
	std::list<Observer*>::iterator it = observerlist_.begin();
	while (it != observerlist_.end())
	{
		(*it)->Update(this);
		++it;
	}
	return;
}

void PrintModel::GetPrintString(std::wstring& str)
{
	str = printstring_;
}

void PrintModel::SetPrintString(const std::wstring* str)
{
	printstring_ = *str;
}

PrintView.cpp
#include "PrintView.h"
#include "PrintModel.h"
#include <string>
#include <iostream>

using std::endl;
using std::wcout;
using std::wstring;

PrintTask::PrintTask(PrintView* view, PrintModel* model)
	:view_(view),model_(model)
{
}

void PrintTask::DoTask()
{
	view_->DoUpdate(model_);
	return;
}


PrintView::PrintView(PrintModel* model)
	:model_(model)
{
}

PrintView::~PrintView(void)
{
}

void PrintView::Update(ModelBase * model)
{
	if (model_==model)
	{
		PrintTask *task = new PrintTask(this, model_);
		PostTaskThread(task);
	}
	return;
}

void PrintView::DoUpdate(ModelBase * model)
{
	if (model_==model)
	{
		wstring str;
		model_->GetPrintString(str);
		wcout<<str<<endl;
	}
	return;
}

void PrintView::HandleTask(TaskBase* task)
{
	wcout<<L"this is calling PrintView::HandleTask"<<endl;
	PrintTask* printtask = (PrintTask*)task;
	printtask->DoTask();
}
ThreadBase.cpp
#include "ThreadBase.h"
#include <string>
#include <iostream>

using std::wcout;
using std::wstring;
using std::endl;

ThreadBase::ThreadBase(void)
	:runflag_(false)
{
	thread_ = ::CreateThread(NULL,
							0,
							ThreadBase::ThreadProc,
							this,
							CREATE_SUSPENDED,
							&threadid_);

	semaphore_ = ::CreateSemaphore(NULL, MAX_TASK_COUNT, MAX_TASK_COUNT, NULL);

	InitializeCriticalSection(&cs_);
}

ThreadBase::~ThreadBase(void)
{
	DeleteCriticalSection(&cs_);
}

// 需要把list的操作搞成執行緒安全的
void ThreadBase::Run()
{
	runflag_ = true;
	ResumeThread(thread_);
	return;
}

void ThreadBase::Terminate()
{
	runflag_ = false;
	return;
}

// 提交非同步任務給該執行緒操作
bool ThreadBase::PostTaskThread(TaskBase* task)
{
	WaitForSingleObject(semaphore_,INFINITE);//暫不處理返回錯誤,這裡應該同時等待退出執行緒的通知

	EnterCriticalSection(&cs_);
	taskqueue_.push(task);
	LeaveCriticalSection(&cs_);

	return false;
}

DWORD ThreadBase::ThreadProc(LPVOID lpParameter)
{
	ThreadBase* threadbase = (ThreadBase*)(lpParameter);
	threadbase->runflag_ = true;
	while(threadbase->runflag_)
	{
		EnterCriticalSection(&threadbase->cs_);
		if (!threadbase->taskqueue_.size())
		{
			LeaveCriticalSection(&threadbase->cs_);
			continue;
		}

		// 從任務佇列取出任務處理
		TaskBase* task = threadbase->taskqueue_.front();
		threadbase->taskqueue_.pop();
		LeaveCriticalSection(&threadbase->cs_);

		if (!ReleaseSemaphore( threadbase->semaphore_, 1, NULL) )
		{
			printf("ReleaseSemaphore error: %d\n", GetLastError());
		}
		threadbase->HandleTask(task);
		delete task;
	}
	return 0;
}


完整的原始碼請參考我的下載資源