我在用MFC写Windows Sockets应用程序时,在服务器端我用如下函数创建工作线程
//创建接受和处理客户端请求线程
DWORD dwThread;
m_hReqAndData=CreateThread(NULL,0,DirAndFileSizeServiceThread,this,0,&dwThread);
CloseHandle(m_hReqAndData);
在工作线程运行到如下语句(红色部分)else//接受客户端数据
{
//得到CClient类实例
CClient *pClient=pServer->GetClient(allSockfd.fd_array[i]);
if (pClient!=NULL)
{
/接受数据
BOOL bRet=pClient->RecvData();
//接受数据错误或者客户端关闭套接字
if (FALSE==bRet)
{
//取出套接字
SOCKET sTemp=allSockfd.fd_array[i];
//从集合中删除
FD_CLR(allSockfd.fd_array[i],&allSockfd);
//从客户端管理链表中删除该客户端
pServer->DeleteClient(sTemp);
pClient=NULL;
//更新界面信息
pServer->ShowClinentNumInfo(allSockfd.fd_count);
}
}
RecvData()函数中运行到m_pServer->ShowReqDirInfo(_T("请求根目录。")); void CServerDlg::ShowReqDirInfo(CString strDir)//显示客户端请求目录
{
m_ctlTip.SetWindowText(strDir);
UpdateData(FALSE);
}
出现如下中断
void CWnd::AssertValid() const
{
if (m_hWnd == NULL)
return; // null (unattached) windows are valid // check for special wnd??? values
ASSERT(HWND_TOP == NULL); // same as desktop
if (m_hWnd == HWND_BOTTOM)
ASSERT(this == &CWnd::wndBottom);
else if (m_hWnd == HWND_TOPMOST)
ASSERT(this == &CWnd::wndTopMost);
else if (m_hWnd == HWND_NOTOPMOST)
ASSERT(this == &CWnd::wndNoTopMost);
else
{
// should be a normal window
ASSERT(::IsWindow(m_hWnd)); // should also be in the permanent or temporary handle map
CHandleMap* pMap = afxMapHWND();
ASSERT(pMap != NULL); CObject* p=NULL;
if(pMap)
{
ASSERT( (p = pMap->LookupPermanent(m_hWnd)) != NULL ||
(p = pMap->LookupTemporary(m_hWnd)) != NULL);
}
ASSERT((CWnd*)p == this); // must be us // Note: if either of the above asserts fire and you are
// writing a multithreaded application, it is likely that
// you have passed a C++ object from one thread to another
// and have used that object in a way that was not intended.
// (only simple inline wrapper functions should be used)
//
// In general, CWnd objects should be passed by HWND from
// one thread to another. The receiving thread can wrap
// the HWND with a CWnd object by using CWnd::FromHandle.
//
// It is dangerous to pass C++ objects from one thread to
// another, unless the objects are designed to be used in
// such a manner.
}
}
查了很多资料,还是搞不懂,我在主线程中向工作线程传递CServerDlg对象指针,在工作线程中调用CServerDlg的UpdataData()更新界面的时候就会出现错误。查了很多资料,还是迷雾一团,请各位高手指点一下,谢了……
//创建接受和处理客户端请求线程
DWORD dwThread;
m_hReqAndData=CreateThread(NULL,0,DirAndFileSizeServiceThread,this,0,&dwThread);
CloseHandle(m_hReqAndData);
在工作线程运行到如下语句(红色部分)else//接受客户端数据
{
//得到CClient类实例
CClient *pClient=pServer->GetClient(allSockfd.fd_array[i]);
if (pClient!=NULL)
{
/接受数据
BOOL bRet=pClient->RecvData();
//接受数据错误或者客户端关闭套接字
if (FALSE==bRet)
{
//取出套接字
SOCKET sTemp=allSockfd.fd_array[i];
//从集合中删除
FD_CLR(allSockfd.fd_array[i],&allSockfd);
//从客户端管理链表中删除该客户端
pServer->DeleteClient(sTemp);
pClient=NULL;
//更新界面信息
pServer->ShowClinentNumInfo(allSockfd.fd_count);
}
}
RecvData()函数中运行到m_pServer->ShowReqDirInfo(_T("请求根目录。")); void CServerDlg::ShowReqDirInfo(CString strDir)//显示客户端请求目录
{
m_ctlTip.SetWindowText(strDir);
UpdateData(FALSE);
}
出现如下中断
void CWnd::AssertValid() const
{
if (m_hWnd == NULL)
return; // null (unattached) windows are valid // check for special wnd??? values
ASSERT(HWND_TOP == NULL); // same as desktop
if (m_hWnd == HWND_BOTTOM)
ASSERT(this == &CWnd::wndBottom);
else if (m_hWnd == HWND_TOPMOST)
ASSERT(this == &CWnd::wndTopMost);
else if (m_hWnd == HWND_NOTOPMOST)
ASSERT(this == &CWnd::wndNoTopMost);
else
{
// should be a normal window
ASSERT(::IsWindow(m_hWnd)); // should also be in the permanent or temporary handle map
CHandleMap* pMap = afxMapHWND();
ASSERT(pMap != NULL); CObject* p=NULL;
if(pMap)
{
ASSERT( (p = pMap->LookupPermanent(m_hWnd)) != NULL ||
(p = pMap->LookupTemporary(m_hWnd)) != NULL);
}
ASSERT((CWnd*)p == this); // must be us // Note: if either of the above asserts fire and you are
// writing a multithreaded application, it is likely that
// you have passed a C++ object from one thread to another
// and have used that object in a way that was not intended.
// (only simple inline wrapper functions should be used)
//
// In general, CWnd objects should be passed by HWND from
// one thread to another. The receiving thread can wrap
// the HWND with a CWnd object by using CWnd::FromHandle.
//
// It is dangerous to pass C++ objects from one thread to
// another, unless the objects are designed to be used in
// such a manner.
}
}
查了很多资料,还是搞不懂,我在主线程中向工作线程传递CServerDlg对象指针,在工作线程中调用CServerDlg的UpdataData()更新界面的时候就会出现错误。查了很多资料,还是迷雾一团,请各位高手指点一下,谢了……
然后主线程调用UpdataData更新界面消息吗?
工作线程中的m_pServer(CServerDlg指针对象)指针调用UpdataData为什么不可以呢?
LRESULT CProtectPage::OnUpdateData(WPARAM wParam, LPARAM lParam)
{
UpdateData(wParam);
return 0;
}
ONUpdateData是自定义的消息函数,WM_UPDATEDATA是自定义消息
至于原因,MFC的窗口是线程相关的,每个窗口的HandleMap是储存在线程相关的堆栈里面的(thread-local-storage (TLS) ),线程环境都切换了当然线程堆栈的数据也就不一样了