关于多线程的一些细节
作者: coolnerd
线程的程序中,如果线程要向界面窗口报告状态,有两种操作方法,
一种是通过消息的方法,由于消息本身携带的消息量有时不购用,往往消息参数
只是一个指向某消息对象的指针,而消息对象往往需要在堆内存中new生成,
(因为往往线程不能等待消息处理完毕就继续执行,所以如果消息对象是栈对象
往往消息对象还未来及被处理,就又被线程修改.所以采用堆对象.)
界面接受到
消息对象后delete之.但是这时界面退出后,如果线程仍然生成新的消息对象,
则消息对象得不到释放,所以在这种情况下,界面接受到WM_CLOSE消息将要释放
之前,要等待线程完全退出之后再真正释放.
线程向界面报告状态的第二种方法是直接在线程的执行过程中同步地(等待,
直到完成称为同步)执行界面显示,这种机制下,要注意在界面显示是需要查看
界面窗口是否仍然存在(使用IsWindow(hWnd)函数实现).
这样做似乎已经完美,但是是不完善的,因为假如有多个view小窗口,如多个
CSplitterWnd,只在一个CSplitterWnd的WM_CLOSE消息的处理函数中进行防范,
其他的CSplitterWnd照常退出,仍然要出问题,所以要抓住根源:
用户使用菜单退出或点击frmae窗口的x按钮退出,接受到退出消息的首先是frameWnd
所以需要在frameWnd的WM_CLOSE函数中进行线程的释放.!
另外,往往线程在Document类的掌管之下,frame怎样访问document对象?
FrameWnd没有直接提供获取document的函数.Document,View,FrameWnd三者的
创建顺序是:doc->Frmae->View,在View::InitUpdate()函数的执行时刻,
可以执行以下代码:
CMainFrame*frm=(CMainFrame*)(AfxGetApp()->m_pMainWnd);
frm->pDoc=GetDocument();
另外:注意需要捕捉WM_CLOSE,而非WM_DESTROY消息,因为WM_CLOSE消息
先于后者.
另外,考查以下代码:
void CThreadList::UpdateThread(int id,CString client,CString msg)
{
EnterCriticalSection(&CThreadList::csUpDateThread);
{
int ItemCount=m_ListCtrl.GetItemCount() ; //ListCtrl
最多65535条记录
if(id>ItemCount)
{
for(int i=0;i<id-ItemCount;i++)
{
LV_ITEM lvi;
lvi.mask = LVIF_TEXT | LVIF_IMAGE
/* |LVIF_STATE */;
lvi.iItem = ItemCount+i;
lvi.iSubItem = 0;
m_ListCtrl.InsertItem(&lvi);
//m_ListCtrl.SetItemCount(id);
}
}
m_ListCtrl.SetItemText(id-1,0,ito10a(id));
m_ListCtrl.SetItemText(id-1,1,client);
m_ListCtrl.SetItemText(id-1,2,msg);
}
LeaveCriticalSection(&CThreadList::csUpDateThread);
}
这就是线程用来调用的界面函数,该界面CThreadList
是个ListCtrl类,该成员函数的参数中,id,client,msg是界面显示的内容
函数首先判断id是否超出现在已经存在的个数,如果超出则增加一到多条记录
这种动态调整记录个数的机制比较诱人,但是如果这个函数是在这样的情况下
被调用: frame窗口接受到了WM_CLOSE消息,在处理消息之前,首先消灭线程
而就在消灭线程的过程中,一个未来及消灭的线程调用了这个函数,该函数在
执行过程中需要执行GetItemCount()函数,跟踪GetItemCount函数,发现它是
依靠执行SendMessage获得ItemCount的(SendMessage函数是个不等到结果不
返回的函数),这时会发生的是死机,因为Windows系统在处理WM_ClOSE消息
未完成时,又被要求处理SendMessage函数,于是SendMessage函数和WM_CLOSE
消息处理过程发生了互相等待的事故.
结论是不要在线程向界面报告状态的过程中调用任何依靠消息工作的函数.
经过考查,几乎所有更新界面控件的函数如SetItemText都是依靠SendMessage
来工作的,所以会到问题的最初:"在多线程的程序中,如果线程要向界面窗口
报告状态,有两种操作方法"在这两种方法中,第二种方法是行不通的.
※ 来源:·BBS 水木清华站 bbs.net.tsinghua.edu.cn·[FROM: 166.111.60.81]
<scrIPT language=JavaScript1.2 src="../article_bottom.js"