首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > VC/MFC >

小弟我想了几天的有关问题,请各位兄弟来看看,小弟我所难!线程传参

2012-01-24 
我想了几天的问题,请各位兄弟来看看,急我所难!!线程传参这个例子是VC++高级编程技术与实例宋哓宇王永会编

我想了几天的问题,请各位兄弟来看看,急我所难!!线程传参
这个例子是   VC++   高级编程技术与实例     宋哓宇     王永会   编著.中国水利水电出版社   2006年1月第一版   价格37.   第五章多线程的一个例子
1:
建立一个基于对话框的程序Test
2:
在对话框上放置一个按钮IDC_BT_START.和一个进度条控件IDC_PROGRESS1
并为IDC_PROGRESS1关联一个变量m_progress;
3:
在TestDlg.h文件中,定义一个结构体
struct   threadInfo
{
CProgressCtrl   *   p_Progress;
CDialog   *   p_Dlg;    
int     second;           //进度条暂停时

}
4:
在TestDlg.cpp文件中
#define   USER_PROC_FINISHED   WM_USER+1

threadInfo   Info;
UINT   ThreadProc(LPVOID   pParam)
{
threadInfo   *   p=(threadInfo   *)pParam;
for(int   i=0;i <=100;i++)
{
p-> p_Progress-> SetPos(i);
::Sleep(p-> second*10);


}
::PostMessage(p-> p_Dlg-> GetSafeHwnd(),USER_PROC_FINISHED,0,0);
return   0;
}
5:
在按钮IDC_BT_START的单击响应中:
void   CTestDlg::OnBtStart()  
{

Info.p_Progress=&m_progress;
Info.p_Dlg=this;
          Info.second=1;
AfxBeginThread(ThreadProc,&Info);
}
6:
在TestDlg.h中声明消息函数

            .........
        //}}AFX_MSG
        afx_msg   void   OnFinish();
7.
在TestDlg.cpp文件中
BEGIN_MESSAGE_MAP(CTestDlg,   CDialog)
                  .......
ON_BN_CLICKED(IDC_BT_START,   OnBtStart)
//}}AFX_MSG_MAP
ON_MESSAGE(USER_PROC_FINISHED,OnFinish)
END_MESSAGE_MAP()

void   CTestDlg::OnFinish()  
{
SetDlgItemText(IDC_BT_START, "线程结束请重新启动 ");
}


在候捷译的 <Win32   多线程程序设计> 书中p294中说:
1:
MFC有一个重大限制,会影响你所做的几乎每一件事情,MFC各对象和Win32   handles之间的映射关系记录在线程局部存贮中(TLS),因此你没有办法把一个MFC对象从某个线程手上交到另一个线程手上,你也不能在线程之间传递MFC对象指针.这里的指针包含(担不限于)CWnd,CDC,CPen,CBrush,CFont,Cbitmap,CPalette........
2:这个限制的意思是说,你不能够放一个指针(指向一个CWnd)到一个结构中,而该结构被一个Worker线程使用,你也不能够把一个指向CDialog或CView的指针交给另一个线程.............在线程之间共享对象,这里倒有一个不大方便的替代方案,不要放置MFC对象,改放对象的handle,你可以利用GetSateHwnd()获得派生自CWnd对象的handle,CDialog.

上各程序中
void   CTestDlg::OnBtStart()  
{

Info.p_Progress=&m_progress;   //传递进度条的地址,不对吧??   进度条派生自CWnd
Info.p_Dlg=this;                           //传递对话框的指针,不对吧??   进度条派生自CWnd
          Info.second=1;
AfxBeginThread(ThreadProc,&Info);
}


threadInfo   Info;
UINT   ThreadProc(LPVOID   pParam)
{
threadInfo   *   p=(threadInfo   *)pParam;
for(int   i=0;i <=100;i++)
{
p-> p_Progress-> SetPos(i);//利用所传进度条的地址,调用进度条的成员函数,不对吧??.
::Sleep(p-> second*10);


}
::PostMessage(p-> p_Dlg-> GetSafeHwnd(),USER_PROC_FINISHED,0,0);
                //(p-> p_Dlg-> GetSafeHwnd()   利用所传对话框的this指针,调用成员函数GetSafeHwnd(),不对吧??.
return   0;
}



[解决办法]
国内的书有很不认真的. 侯捷是对的, MSDN上也是这么说的.

通过传递HANDLE而不是对象的指针, 你可以在你的worker thread中用CWnd::FromHandle或CWnd::Attach来将HANDLE绑定到在你这个worker thread中的一个C++对象上.

还可以通过给主线程PostMessage来完成一定的工作
[解决办法]


你确定m_progress确实拥有一个有效的m_hWnd吗?

或者是不是没有testdlg.Detach()的原因?
[解决办法]

testdlg.Attach((HWND)pParam);
一个窗口应该只能被一个对象Attach吧.我跟踪了下,点击 "开始 "按钮之后的断言,就出现在这里.

这样做,可以使testdlg.Attach((HWND)pParam);运行成功:

AfxBeginThread(ThreadProc,this-> Detach());
在现成结束之后,再 this-> Attach...

但是同样没有任何意义,因为在testdlg Attach成功之后,监视可以发现,testdlg的成员变量m_progress1为NULL,这样运行到
testdlg.m_progress.SetPos(i);这句话时,是肯定会出现内存错误的.

其实说的是往线程传参数是,最好是handle,但是前面传指针,还不是用的好好的?干麻非要传handle呢?handle作为参数传进去的时候,好象做PostMessage(..)的第一个参数时,是没有什么问题的,至于为什么不能用他来操作窗口,那就要等牛人出现给个解释了!

[解决办法]
1.传对象指针是可以的
2.但不能调用与句柄映射有关的函数。比如CWnd::GetDlgItem().只要不导致下面这个函数和其它句柄映射有关的函数,就可以。

CWnd* PASCAL CWnd::FromHandle(HWND hWnd)
{
CHandleMap* pMap = afxMapHWND(TRUE); //create map if not exist
ASSERT(pMap != NULL);
CWnd* pWnd = (CWnd*)pMap-> FromHandle(hWnd);

#ifndef _AFX_NO_OCC_SUPPORT
pWnd-> AttachControlSite(pMap);
#endif

ASSERT(pWnd == NULL || pWnd-> m_hWnd == hWnd);
return pWnd;
}

热点排行