实现程序已启动就开始3条线程。
1条调用DOC内的画图函数。
2条调用VIEW内的画图函数。
【STEP 1】. 写好类画图函数
void CTView::Rect(void)
{
CClientDC dc(this);
dc.Rectangle(10, 10, 200, 200);
}
void CTView::Ellipse(void)
{
CClientDC dc(this);
dc.Ellipse(250, 250, 470, 470);
}
void CTDoc::Calculate(void)
{
HDC hdc = ::GetDC(AfxGetMainWnd()->m_hWnd);
::Ellipse(hdc, 50, 50, 200, 200);
::ReleaseDC(AfxGetMainWnd()->m_hWnd, hdc);
}
【STEP 2】. 构建一个类,专门调用以上函数,声明以下函数为静态。
UINT CThreadFunc::DrawEll(LPVOID lpParam)
{
Pointer* pt1 = (Pointer*) lpParam;
CTView* pv =(CTView* ) pt1->pv;
while(!shut)
pv->Ellipse();
return 0;
}
UINT CThreadFunc::DrawRect(LPVOID lpParam)
{
Pointer* pt1 = (Pointer*) lpParam;
CTView* pv =(CTView* ) pt1->pv;
while(!shut)
pv->Rect();
return 0;
}
UINT CThreadFunc::Calculate(LPVOID lpParam)
{
Pointer* pt1 = (Pointer*) lpParam;
CTDoc* pd = (CTDoc* ) pt1->pd;
while (!shut)
pd->Calculate();
return 0;
}
其中 shut为全局变量,让线程退出,不然死循环突然关闭窗口的时候会
导致内存泄露, 在Distroy让shut为真。不能在Onclose,试过了没用。
void CTView::OnDestroy()
{
CFormView::OnDestroy();
shut = true;
delete pt;
}
【STEP 3】. CTApp类的InitiInstance开始调用线程:
CTView * pv = (CTView*)((CFrameWnd*)(AfxGetMainWnd()))->GetActiveView();
CTDoc * pd = (CTDoc*)((CFrameWnd*)(AfxGetMainWnd()))->GetActiveDocument();
pt->pd = pd;
pt->pv = pv;
AfxBeginThread(CThreadFunc::DrawRect, pt);
AfxBeginThread(CThreadFunc::Calculate, pt);
AfxBeginThread(CThreadFunc::DrawEll, pt);
注意: CTApp.h里定义
extern bool shut;
struct Pointer
{
CTView* pv;
CTDoc* pd;
};
extern Pointer* pt ; // 在ondistroy删除,否则泄露,试过在AfxBeginThread后面删除,似乎没用。
===================================
关键在与pView和pDoc怎么传入进去,3种方法
===================================
【方法一】使用指针结构体函数,注意要new一个指针,结束的时候要删除。
【方法二】传递this指针。不需传递结构体指针,也就省去了删除指针导致内存泄露的担心。
只需吧CTApp* 穿进去就可以了。
创建线程处代码改为:
AfxBeginThread(CThreadFunc::DrawRect, this);
AfxBeginThread(CThreadFunc::Calculate, this);
AfxBeginThread(CThreadFunc::DrawEll, this);
这里的this就是CTApp*
然后在线程回调函数里写:
CTApp* p = (CTApp*)(lpParam);
CTView * pv = (CTView*)((CFrameWnd*)(p->GetMainWnd()))->GetActiveView();
while(!shut)
pv->Ellipse();
这样简单多了。
后来验证,穿进去this指针只能够在线程函数里面调用pView,对于pDoc行不通。
所以,干脆利用this指针去调用pv,然后让pv去调用pDoc.
这样就需要在CTView里定义全局变量
CTDoc* pd,在OnInitiUpdate()函数里面
pd = GetDocument();
这样在线程函数中使用Doc应该:
CTApp* p = (CTApp*)(lpParam);
CTView * pv = (CTView*)((CFrameWnd*)(p->GetMainWnd()))->GetActiveView();
CTDoc* pd = pv->pd;
【方法三】对要用到pDoc的,不传进去。直接在线程函数里面定义
CTDoc* pd = (CTDoc*) RUNTIME_CLASS(CTDoc) // 在CTView里学来的。
拿来用还真可以。对CTView不适用。
【方法四】最简单的,干脆定义全局的指针指向视图和文档。
CTDoc* pd;
CTView* pv;
在CTView::OnInitUpdate()里
pd = GetDocument();
pv = this;
就可以了。
注意:如果在App里面的InitInstance里通过
CTView * pv = (CTView*)((CFrameWnd*)(AfxGetMainWnd()))->GetActiveView();
CTDoc * pd = (CTDoc*)((CFrameWnd*)(AfxGetMainWnd()))->GetActiveDocument();
来,得不到正确的,画的图会在外面,不知道为什么。
=======================
总结:
pDoc指针的得到: (1)RUNTIME_CLASS (2)结构体指针传入 (3)用pView调用。
pView指针的得到:(1)this指针传入 (2) 结构体指针的传入 (3)直接传入pView指针。
//==============================
有进程时,在进程函数A里
A
{
pd->F();
}
F()
{
pv = ...AfxGetMainWnd()->...
}
运行到pv会出错。
把AfxGetMainWnd改成theApp.GetMainWnd(),就可以了。
姑且猜测每个线程有个MainWnd还是什么的,反正theApp是唯一的,最安全了