问题描述

         Tcp网络通信中,服务器端接收到来自客户端的连接请求并成功的建立连接,当收到来自客户端的数据时,对数据进行解析,并实现对应操作,有需要的话将在对话框中显示相应信息。通信过程中,在服务器端建立了三个线程完成主要工作,一个监听连接请求线程,另两个为来自两个客户端的数据接收监听。在接收数据解析时,将信息显示到编辑框时报错,(在线程中调用printfMsg()就出错,其他函数中调用不出错),如下所示:

liuxin-线程调用Updatedata函数出错的解决办法

显示部分调用了一个自定义函数:printfMsg()

liuxin-线程调用Updatedata函数出错的解决办法

报错原因分析

经查博文及资料得知问题出在线程中不能直接调用UpdateData()函数。

MFC对象不支持多线程操作,不能供多个线程进程使用。子线程调用pDlg-> UpdateData(FALSE)时主线程(界面线程)会阻塞,更新必须由它完成,这样就形成死锁。UpdateData()函数属于CDialog类的保护成员函数,在工作线程中不能使用UpdateData来更新主线程中的数据。更改界面的操作最好用主线程(界面线程),要想在子线程(工作线程)里执行界面线程的操作,可以通过向主线程发送消息来解决。

解决方法

方法有三:

1. 创建线程时使用AfxBeginThread创建CWinThread继承类,参数传递时最好传递窗口句柄(主线程向子线程传递对象不安全),使用PostMessageSendMessage消息传递函数向主窗口发送自定义消息,在主窗口中对自定义消息进行处理并更新。

2. 使用control变量或直接获取控件指针进行更新:

dlg->m_editCtl.SetWindowText(dlg->m_value2);

dlg->GetDlgItem(IDC_EDIT2)->SetWindowText(dlg->m_value2);

3. 最简单的办法,将Debug改为Release正常运行。

具体操作

采用了方法一进行了修改,成功实现显示,(方法23未验证)步骤如下:

1.  MFC添加自定义消息

由于MFC中无法通过类向导来自定义消息,所以需要手动添加,主要过程如下:

1)定义消息

xxDlg.h文件中添加:#define WM_UPDATEDATA(WM_USER+100)

【由于很多新控件也会用到WM_USER消息,所以定义WM_USER+100或更高,避免冲突。看到有的博文说将消息定义到stdafx.h文件中(Resource.h文件由系统维护,经常出现自定义的消息丢失。),也有博文说直接加到xxDlg.h中,在此采用后者。】

liuxin-线程调用Updatedata函数出错的解决办法

2)声明消息响应函数

依然在当前xxDlg.h中,添加消息响应函数,在DECLARE_MESSAGE_MAP前面。

liuxin-线程调用Updatedata函数出错的解决办法

3)实现消息响应函数

参考博文中说明:由于在vs2008中未定义ON_MESSAGE_VOID,所以定义的消息响应函数必须有返回值,即LRESULT;而消息参数是WPARAMwParamLPARAM lParam

xxDlg.cpp中,添加如下程序:

liuxin-线程调用Updatedata函数出错的解决办法

4)将消息映射到消息处理函数

放在AFX_MSG_MAP之前,把WM_UPDATEDATA消息映射到消息响应函数OnUpdateData,作如下添加:

liuxin-线程调用Updatedata函数出错的解决办法

5)发送自定义消息

         备注:将该步骤的添加注释掉之后不影响需要实现的功能,原因暂时未知。

以下函数是在一个新的线程中调用的,推荐使用SendMessageTimeout函数,PostMessageSendMessageSendMessageTimeout均可用。

xxDlg.h下添加新线程:

static UINT  SendMsgThread(LPVOIDlpParam);

xxDlg.cpp下添加相应程序:

liuxin-线程调用Updatedata函数出错的解决办法


2. 在原工程中,将printfMsg()改动:

liuxin-线程调用Updatedata函数出错的解决办法

至此,改动添加完毕。

可接收到数据并显示对应信息:

liuxin-线程调用Updatedata函数出错的解决办法

另外,参考博文上说:

【如果用户需要一个定义整个系统唯一的消息,可以调用SDKRegisterWindowMessage定义消息:Resource.h中将代码#define   WM_UPDATEDATA    (WM_USER + 100)

修改为static UINT WM_UPDATEDATA=RegisterWindowMessage(_T("User"));并使用ON_REGISTERED_MESSAGE宏指令取代ON_MESSAGE宏指令,其余步骤同上。
注:如果仍然使用ON_MESSAGE宏指令,compile可以通过,但是无法响应消息。】

暂未验证该方法。



相关文章: