多线程编程中的主界面安全处理

本文探讨了在多线程编程中直接操作主界面对象的危险性,指出这种做法可能导致死锁。作者建议避免工作线程直接操作界面,而应使用全局缓冲、锁和消息映射机制来保证线程安全。通过创建类来存储消息数据,并使用PostMessage进行通信,以避免线程冲突。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 现在,随着多核心CPU的流行,很多开发人员,不管自己的程序是否适合用多线程,都会使用多线程编程,通常就是一个主界面线程加N个工作线程,而且,常常用单线程编程的思维来操作主界面,将某些界面对象,例如CList,传到工作线程中去,让工作线程直接操作界面对象,大多数情况下,还可以运行的挺好,没问题,但是真的没问题吗?哈,问题大了。例如
UNIT MyWorkThread(LPVOID pParam)
{
....
CList * plist;
plist=(CList *)pParam;
CString str;
int i,iresult;
for(...)
{
   //something you do
   str.Format("Hi , this is work thread :%d , current result is:%d",i,iresult);
   plist->AddString(str);
}

return 0;
}
这样的代码多的不得了,而且,在很多时候,它会正常工作的,但是,它不安全,为什么呢?很多书籍,包括WINDOWS核心编程,[当然UNIX中书籍里讲到主界面的就更少了],都没有提及,主界面的操作其实是个带锁的操作,也就是操作系统将强制保证,同一时间一个进程内最多只有一个界面操作,例如你的消息响应函数就是一个界面操作,不管你的电脑有几个CPU核心,不管你的进程有多少个工作线程,一个界面同一时间只能有一个操作,其他操作将被阻塞,直到前一操作完成。 上面这样的代码,违反了 工作线程不直接操作界面对象 的规则,是很危险的,代码量一大,用到具体的程序中,很容易导致死锁定,例如,在网络程序中,假如采用这样的代码,当连接断开的时候,主界面收到消息,要断开连接,并等待工作线程退出,而工作线程正等待修改主界面对象,而主界面对象的操作,由于正在执行断开消息的响应,在等待工作线程结束,这样就发生了死锁,这个教训我是在开发FtpAnywhere客户端软件的时候,经历了上百次的模拟才发现问题的根本并解决的,不过你的运气比较好,因为前面已经有我给你铺了路,你可以少走很多歪路了。。。。。。

这种方法不行,于是,有人改进了,采用发送消息的方法,我见得太多了,说实话,从看见的第一眼起,我就觉得,用这个代码的人可能对多线程和对象安全根本没概念.....
AfxGetMainWnd( )->PostMessage(.....)
它将(const char *)str作为lparam参数传递过去了,汗,大汗啊,CString对象是线程安全吗?准确的说,CString类是线程安全,但是它的具体对象,则不是线程安全,在跨线程的调用中,必须被同步保护,如果在主界面响应消息前,str中的缓冲被重新分配了,怎么办?内容修改了,怎么办?也许,你100次运行前99次都成功了,你能保证第100次也能成功?其实,稍微用点心思,就可以发现问题了,两个线程中的CString,没有任何同步,出问题是正常,不出问题,那才是见鬼了

既然直接操作界面对象不行,用消息传递也不理想,那么如何解决呢?其实很简单,

全局 缓冲->一般需要你自己编写一个类,然后用CArray或者vector等定义为一个数组,用来缓冲各类消息
锁->这是针对全局缓冲的,多线程操作中,对这个消息缓冲必须加锁
消息映射->定义在全局缓冲中加了需要操作的界面数据后,发送什么消息,例如 WM_USER+1
一个简单点的数据定义
Class MyMsgClass
{
public:
  int itype;//消息类型
  int iobj;//修改哪个界面对象,例如EDIT还是LIST或者其它
  CString str;//字符串消息....
  .....你自己的其他定义
  .........
}


当工作线程有数据需要显示,
加锁,
MyMsgClass然后放到全局缓冲
解锁
并给主界面一个消息 AfxGetMainWnd( )->PostMessage(...)


主界面接到消息后
主界面会调用消息响应函数,该函数执行
加锁
从全局缓冲读数据,并删除缓冲中指定数据MyMsgClass
解锁
然后根据MyMsgClass中的信息,主界面负责写数据到具体的界面对象

这种操作方法也许不是最高效,但是它是多线程安全的,因为它是用我自己代码的无数次失败换来的,如果你有更高效的处理方法,请告诉我,非常感谢您。
danscort#nbip.net   #请换成@

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值