求mfc线程问题, 20
在mfc中新建一个进程例如UINTCmfcApp::ThreadFunc(LPVOIDpParam){//线程函数实现m_m1="fdf";UpdateData(FALS...
在mfc中新建一个进程例如
UINT CmfcApp::ThreadFunc(LPVOID pParam)
{
//线程函数实现
m_m1="fdf";
UpdateData(FALSE);
return 1;
}
可是有错误,我是想在线程中给编辑框赋值并显示,可是不行,请高手应该怎么弄,才能在线程中改变编辑框的内容 展开
UINT CmfcApp::ThreadFunc(LPVOID pParam)
{
//线程函数实现
m_m1="fdf";
UpdateData(FALSE);
return 1;
}
可是有错误,我是想在线程中给编辑框赋值并显示,可是不行,请高手应该怎么弄,才能在线程中改变编辑框的内容 展开
2个回答
展开全部
子线程中不能操作主线程的控件具,体实现方法见上个提问,另外,UpdateData不要在子线程中用会卡的!
以下是我搜集的MFC多线程应注意的事项,很乱但很有用:
--------------------------------------------------------------------------------
MFC多线程编程注意事项 -
--------------------------------------------------------------------------------
关于启动线程时传输窗口对象(指针?句柄?)的问题:
在选择菜单中的开始线程后:
void cmainframe::onmenu_start()
{
...
afxbeginthread(mythread, this);
...
}
线程函数如下:
uint mythread(lpvoid pparam)
{
cmainframe* pmainfrm = (cmainframe *)pparam;
...
}
问题一:
这样的代码是不是有问题?
(文档中说线程间不能直接传输mfc对象的指针,应该通过传输句柄实现)
问题二:
这样使用开始好像没有问题,直接通过pmainfrm访问窗口中的view都正常。
但发现访问状态条时:
pmainfrm->m_wndstatusbar.setpanetext(2, "test);
出现debug assertion failed!(在窗口线程中没有问题)
位置是wincore.cpp中的
assert((p = pmap->lookuppermanent(m_hwnd)) != null ||
(p = pmap->lookuptemporary(m_hwnd)) != null);
为什么访问view能正常,但访问状态条时不可以呢?
问题三:
如果通过传输句柄实现,怎样做呢?
我用下面的代码执行时有问题:
void cmainframe::onmenu_start()
{
...
hwnd hwnd = getsafehwnd();
afxbeginthread(mythread, hwnd);
...
}
uint mythread(lpvoid pparam)
{
cmainframe* pmainfrm = (cmainframe *)(cwnd::fromhandle((hwnd)pparam));
...
}
执行时通过线程中得到pmainfrm,访问其成员时不正常。
网友:hewwatt
大致原因解释如下:
1. mfc的大多数类不是线程安全的,cwnd及其消息路由是其中之最
2. mfc界面类的大多数方法,最后都是通过sendmessage实现的,而消息处理的
过程中会引发其他消息的发送及处理。如果消息处理函数本身不是线程安全的
你从工作线程中调用这些方法迟早会同你界面线程的用户消息响应发生冲突
3. cxxxx::fromhandle会根据调用者所在线程查表,如果查不到用户创建的cxxxx
对应对象,它会创建一个临时对象出来。由于你在工作线程中调用该方法,当然不可能查到界面主线程中你所建立起来的那个对象了。这时mfc会你创建一个临时对象并返回给你,你根本不可能期望它的成员变量会是有意义的。
所以要用也只能用cwnd::fromhandle,因为它只包含一个m_hwnd成员。 不过,要记住
跨线程直接或间接地调用::sendmessage,通常都是行为不可预测的。
1.工作线程给主线程发消息使用的是SendMessage和PoseMessage函数。这两个函数的区别在于SendMessage函数是阻塞方式,而PoseMessage函数是非阻塞方式。如果不是严格要求工作线程与主线程必须同步执行,则推荐使用PoseMessage。
2.不要在线程函数体内操作MFC控件,因为每个线程都有自己的线程模块状态映射表,在一个线程中操作另一个线程中创建的MFC对象,会带来意想不到的问题。更不要在线程函数里,直接调用UpdataData()函数更新用户界面,这会导致程序直接crash。而应该通过发送消息给主线程的方式,在主线程的消息响应函数里操作控件。
3.在主线程中不要使用WaitForSingleObject和WaitForMultipleObjects两个函数等待线程退出,其原因就是有导致程序死锁的隐患,特别是线程函数里调用了SendMessage或是直接操作了MFC对象,更易出现此种现象。为解决这一问题,微软特提供了一个函数,MsgWaitForMultipleObjects。
照着网上的例子,写了在主线程中等待单个线程退出的程序:
DWORD dRet=-2;
MSG msg;
BOOL bWaitAll=FALSE;
int nWaitCount=2; //初始等待的线程数目
while (1)
{
dRet=MsgWaitForMultipleObjects(1,句柄的指 针,bWaitAll,INFINITE,QS_ALLINPUT);
if (dRet == WAIT_OBJECT_0 + 1)
{
TRACE("收到消息,函数返回值为%d \n",dRet);
while (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
else if (dRet == WAIT_OBJECT_0 )
{
TRACE("线程退出了\n");
break;
}
}//end while
}
实际使用中,在主线程中使用WaitForMultipleObjects导致界面线程在子线程结束前失去响应,而使用MsgWaitForMultipleObjects则很好的解决了这个问题。
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/nefeithu123/archive/2009/06/07/4250002.aspx
1、尽量少的使用全局变量、static变量做共享数据,尽量使用参数传递对象。被参数传递的对象,应该只包括必需的成员变量。所谓必需的成员变量,就是必定会被多线程操作的。很多人图省事,会把this指针(可能是任意一个对象指针)当作线程参数传递,致使线程内部有过多的操作权限,对this中的参数任意妄为。整个程序由一个人完成,可能会非常注意,不会出错,但只要一转手,程序就会面目全非。当两个线程同时操作一个成员变量的时候,程序就开始崩溃了,更糟的是,这种错误很难被重现。(我就在郁闷这个问题,我们是几个人,把程序编成debug版,经过数天使用,才找到错误。而找到错误只是开始,因为你要证明这个bug被修改成功了,也非常困难。)其实,线程间数据交互大多是单向的,在线程回调函数入口处,尽可能的将传入的数据备份到局部变量中(当然,用于线程间通讯的变量不能这么处理),以后只对局部变量做处理,可以很好的解决这种问题。
2、在MFC中请慎用线程。因为MFC的框架假定你的消息处理都是在主线程中完成的。首先窗口句柄是属于线程的,如果拥有窗口句柄的线程退出了,如果另一个线程处理这个窗口句柄,系统就会出现问题。而MFC为了避免这种情况的发生,使你在子线程中调用消息(窗口)处理函数时,就会不停的出Assert错误,烦都烦死你。典型的例子就时CSocket,因为CSocket是使用了一个隐藏窗口实现了假阻塞,所以不可避免的使用了消息处理函数,如果你在子线程中使用CSocket,你就可能看到assert的弹出了。
3、不要在不同的线程中同时注册COM组件。两个线程,一个注册1.ocx, 2.ocx, 3.ocx, 4.ocx; 而另一个则注册5.ocx, 6.ocx, 7.ocx, 8.ocx,结果死锁发生了,分别死在FreeLibrary和DllRegisterServer,因为这8个ocx是用MFC中做的,也可能是MFC的Bug,但DllRegisterServer却死在GetModuleFileName里,而GetModuleFileName则是个API唉!如果有过客看到,恰巧又知道其原因,请不吝赐教。
4、不要把线程搞的那么复杂。很多初学者,恨不能用上线程相关的所有的函数,这里互斥,那里等待,一会儿起线程,一会儿关线程的,比起goto语句有过之而无不及。好的多线程程序,应该是尽量少的使用线程。这句话怎么理解呐,就是说尽量统一一块数据共享区存放数据队列,工作子线程从队列中取数据,处理,再放回数据,这样才会模块化,对象化;而不是每个数据都起一个工作子线程处理,处理完了就关闭,写的时候虽然直接,等维护起来就累了。
以下是我搜集的MFC多线程应注意的事项,很乱但很有用:
--------------------------------------------------------------------------------
MFC多线程编程注意事项 -
--------------------------------------------------------------------------------
关于启动线程时传输窗口对象(指针?句柄?)的问题:
在选择菜单中的开始线程后:
void cmainframe::onmenu_start()
{
...
afxbeginthread(mythread, this);
...
}
线程函数如下:
uint mythread(lpvoid pparam)
{
cmainframe* pmainfrm = (cmainframe *)pparam;
...
}
问题一:
这样的代码是不是有问题?
(文档中说线程间不能直接传输mfc对象的指针,应该通过传输句柄实现)
问题二:
这样使用开始好像没有问题,直接通过pmainfrm访问窗口中的view都正常。
但发现访问状态条时:
pmainfrm->m_wndstatusbar.setpanetext(2, "test);
出现debug assertion failed!(在窗口线程中没有问题)
位置是wincore.cpp中的
assert((p = pmap->lookuppermanent(m_hwnd)) != null ||
(p = pmap->lookuptemporary(m_hwnd)) != null);
为什么访问view能正常,但访问状态条时不可以呢?
问题三:
如果通过传输句柄实现,怎样做呢?
我用下面的代码执行时有问题:
void cmainframe::onmenu_start()
{
...
hwnd hwnd = getsafehwnd();
afxbeginthread(mythread, hwnd);
...
}
uint mythread(lpvoid pparam)
{
cmainframe* pmainfrm = (cmainframe *)(cwnd::fromhandle((hwnd)pparam));
...
}
执行时通过线程中得到pmainfrm,访问其成员时不正常。
网友:hewwatt
大致原因解释如下:
1. mfc的大多数类不是线程安全的,cwnd及其消息路由是其中之最
2. mfc界面类的大多数方法,最后都是通过sendmessage实现的,而消息处理的
过程中会引发其他消息的发送及处理。如果消息处理函数本身不是线程安全的
你从工作线程中调用这些方法迟早会同你界面线程的用户消息响应发生冲突
3. cxxxx::fromhandle会根据调用者所在线程查表,如果查不到用户创建的cxxxx
对应对象,它会创建一个临时对象出来。由于你在工作线程中调用该方法,当然不可能查到界面主线程中你所建立起来的那个对象了。这时mfc会你创建一个临时对象并返回给你,你根本不可能期望它的成员变量会是有意义的。
所以要用也只能用cwnd::fromhandle,因为它只包含一个m_hwnd成员。 不过,要记住
跨线程直接或间接地调用::sendmessage,通常都是行为不可预测的。
1.工作线程给主线程发消息使用的是SendMessage和PoseMessage函数。这两个函数的区别在于SendMessage函数是阻塞方式,而PoseMessage函数是非阻塞方式。如果不是严格要求工作线程与主线程必须同步执行,则推荐使用PoseMessage。
2.不要在线程函数体内操作MFC控件,因为每个线程都有自己的线程模块状态映射表,在一个线程中操作另一个线程中创建的MFC对象,会带来意想不到的问题。更不要在线程函数里,直接调用UpdataData()函数更新用户界面,这会导致程序直接crash。而应该通过发送消息给主线程的方式,在主线程的消息响应函数里操作控件。
3.在主线程中不要使用WaitForSingleObject和WaitForMultipleObjects两个函数等待线程退出,其原因就是有导致程序死锁的隐患,特别是线程函数里调用了SendMessage或是直接操作了MFC对象,更易出现此种现象。为解决这一问题,微软特提供了一个函数,MsgWaitForMultipleObjects。
照着网上的例子,写了在主线程中等待单个线程退出的程序:
DWORD dRet=-2;
MSG msg;
BOOL bWaitAll=FALSE;
int nWaitCount=2; //初始等待的线程数目
while (1)
{
dRet=MsgWaitForMultipleObjects(1,句柄的指 针,bWaitAll,INFINITE,QS_ALLINPUT);
if (dRet == WAIT_OBJECT_0 + 1)
{
TRACE("收到消息,函数返回值为%d \n",dRet);
while (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
else if (dRet == WAIT_OBJECT_0 )
{
TRACE("线程退出了\n");
break;
}
}//end while
}
实际使用中,在主线程中使用WaitForMultipleObjects导致界面线程在子线程结束前失去响应,而使用MsgWaitForMultipleObjects则很好的解决了这个问题。
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/nefeithu123/archive/2009/06/07/4250002.aspx
1、尽量少的使用全局变量、static变量做共享数据,尽量使用参数传递对象。被参数传递的对象,应该只包括必需的成员变量。所谓必需的成员变量,就是必定会被多线程操作的。很多人图省事,会把this指针(可能是任意一个对象指针)当作线程参数传递,致使线程内部有过多的操作权限,对this中的参数任意妄为。整个程序由一个人完成,可能会非常注意,不会出错,但只要一转手,程序就会面目全非。当两个线程同时操作一个成员变量的时候,程序就开始崩溃了,更糟的是,这种错误很难被重现。(我就在郁闷这个问题,我们是几个人,把程序编成debug版,经过数天使用,才找到错误。而找到错误只是开始,因为你要证明这个bug被修改成功了,也非常困难。)其实,线程间数据交互大多是单向的,在线程回调函数入口处,尽可能的将传入的数据备份到局部变量中(当然,用于线程间通讯的变量不能这么处理),以后只对局部变量做处理,可以很好的解决这种问题。
2、在MFC中请慎用线程。因为MFC的框架假定你的消息处理都是在主线程中完成的。首先窗口句柄是属于线程的,如果拥有窗口句柄的线程退出了,如果另一个线程处理这个窗口句柄,系统就会出现问题。而MFC为了避免这种情况的发生,使你在子线程中调用消息(窗口)处理函数时,就会不停的出Assert错误,烦都烦死你。典型的例子就时CSocket,因为CSocket是使用了一个隐藏窗口实现了假阻塞,所以不可避免的使用了消息处理函数,如果你在子线程中使用CSocket,你就可能看到assert的弹出了。
3、不要在不同的线程中同时注册COM组件。两个线程,一个注册1.ocx, 2.ocx, 3.ocx, 4.ocx; 而另一个则注册5.ocx, 6.ocx, 7.ocx, 8.ocx,结果死锁发生了,分别死在FreeLibrary和DllRegisterServer,因为这8个ocx是用MFC中做的,也可能是MFC的Bug,但DllRegisterServer却死在GetModuleFileName里,而GetModuleFileName则是个API唉!如果有过客看到,恰巧又知道其原因,请不吝赐教。
4、不要把线程搞的那么复杂。很多初学者,恨不能用上线程相关的所有的函数,这里互斥,那里等待,一会儿起线程,一会儿关线程的,比起goto语句有过之而无不及。好的多线程程序,应该是尽量少的使用线程。这句话怎么理解呐,就是说尽量统一一块数据共享区存放数据队列,工作子线程从队列中取数据,处理,再放回数据,这样才会模块化,对象化;而不是每个数据都起一个工作子线程处理,处理完了就关闭,写的时候虽然直接,等维护起来就累了。
推荐律师服务:
若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询