beyard

常用链接

统计

最新评论

多线程画图

实现程序已启动就开始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是唯一的,最安全了

posted on 2009-03-30 17:53 阅读(1096) 评论(0)  编辑 收藏 引用


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理