C++實現一個簡單的雙執行緒MVC框架
阿新 • • 發佈:2019-01-27
花了一上午,初步實現一個簡單的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;
}
完整的原始碼請參考我的下載資源