在软件项目里有三个模块,分别为
一个应用模块(处理数据)
一个显示模块(屏幕)
一个通信模块(与主机通信)
每个模块都会继承WINDOW收发通信模块基类创建一个属于自己的子窗口,然后在窗口的消息处理函数中对收到的消息进行处理。
在其中一个测试过程中,当通信模块收到主机命令然后向应用模块发送指令,应用模块执行完后,应用模块会向通信模块发送指令执行成功消息。调用
ret = ::SendMessageTimeout(hRecvWnd,// handle to window
WM_COPYDATA,// message type
(WPARAM)hSendWnd,// first message parameter
(LPARAM)&cds,// second message parameter
SMTO_BLOCK,// send options
3000,// time-out duration
&dwResult);// return value for synchronous call
没想到最后执行超时了2次,最后一次才成功。延迟了9秒。
原因是当应用模块发送消息后,基类窗口处理函数调用的接收到的消息处理动作阻塞住了。
解决阻塞有3种方法
1. 把接受到的消息内容,先拷贝起来,然后直接给发送信息的窗口返回消息处理,然后继续对接受到的消息进行处理.
2. 每收到一个消息,创建一个线程,把收到的消息内容存储起来,然后在线程里对接受到的消息进行处理。
3. 把所有接受到的消息内容,拷贝到队列里,然后对队列里的接受到的消息进行处理
最后我选择了用线程,因为这个比较简单,而且线程数量也不多,释放也简单。
原来的窗口消息处理函数为
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_COPYDATA:
COPYDATASTRUCT* cds = (COPYDATASTRUCT*)lParam;
if ((cds!=NULL)&&(m_ipc!=NULL))
{
//m_ipc为CIPC的类对象,
m_ipc->OnReceive(m_csSendWndTile,cds->dwData,cds->lpData,cds->cbData);
}
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
修改后的窗口消息处理函数为:
UINT Thread_Process(LPVOID lpContext)
{
COPYDATASTRUCT* cds = new COPYDATASTRUCT;
memcpy(cds,(COPYDATASTRUCT*)lpContext,sizeof(COPYDATASTRUCT));
if ((cds!=NULL)&&(g_pIPC!=NULL))
{
g_pIPC->OnReceive("",cds->dwData,cds->lpData,cds->cbData);
}
delete []cds;
AfxEndThread(0);
return 0;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_COPYDATA:
CString appName = AfxGetAppName();
//因为只有应用模块发送消息的时候才会阻塞,而且如果显示模块也用线程的话,那每个线程都带有一个显示屏幕。
//不好处理。通信模块需要自己给自己发送消息,所以如果创建线程的后,就涉及到线程间通信的问题,所以这两个
//模块没有用线程。实际证明也不需要。
if (appName.Compare("通信模块")==0 || appName.Compare("显示模块")==0) //
{
COPYDATASTRUCT *cds = (COPYDATASTRUCT*)lParam;
if ((cds!=NULL)&&(g_pIPC!=NULL))
{
g_pIPC->OnReceive("",cds->dwData,cds->lpData,cds->cbData);
}
}
else
{
AfxBeginThread(Thread_Process,(COPYDATASTRUCT*)lParam);
}
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}