【求助】MsgWaitForMultipleObjects 函数的问题

Squall001 2014-05-18 02:26:55
这个问题是来自我上一个提问的帖子 http://bbs.csdn.net/topics/390790125
上一个问题帖子的解决办法就是这个帖子的做法,但是又遇到新问题。。。

下面是我的代码, 然后再引出问题:
这是一个基于对话框的程序,
首先在头文件里面有几个变量的声明:

BOOL runflag; //这个为否正在发送数据的标志
int uiButton; //这个是表明哪一个函数启动的发送线程 的标志

HANDLE m_CANEvent;
HANDLE m_CANSendThreadHandle[3]; //这里定义3个handle 实际只用一个
CWinThread *pCANThreads;


下面是CPP里面的代码

BOOL CExample2Dlg::OnInitDialog()
{
CDialog::OnInitDialog();


m_CANEvent=CreateEvent(NULL,FALSE,FALSE,NULL); //声明一个事件
runflag=0; //线程运行标志置0

return TRUE; // return TRUE unless you set the focus to a control
}

void CExample2Dlg::OnButton1() //这是一个按钮响应函数,用按钮开启线程的函数
{
DWORD result ;
MSG msg ;
if(runflag==1) //如果线程正在运行
{
SetEvent(m_CANEvent); //发出让线程结束
while(1)
{
result=MsgWaitForMultipleObjects(1,m_CANSendThreadHandle,FALSE,INFINITE,QS_ALLINPUT);
if (result == WAIT_OBJECT_0) //如果等到线程结束 就执行下面的break;
{
break;
}
else
{
while (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) //线程没有结束 就分发消息
{
TRACE("收到消息,函数返回值为%d /n",result);
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
}
ResetEvent(m_CANEvent); //设置无信号,让线程进入等待超时的工作
uiButton=1; //标记这是按钮响应的函数启动的线程
pCANThreads=AfxBeginThread(MyThread1,this);
m_CANSendThreadHandle[0]=pCANThreads->m_hThread; //赋值handle
runflag=1;
Sleep(1000); //故意延迟1秒 让开启的线程跑一跑
}

UINT CExample2Dlg::MyThread1(void *param)
{
CExample2Dlg *Dlg=(CExample2Dlg *)param;
int i;
CString tmp;
DWORD dw;
//在进入下面循环前,在我那个真实程序前,还有不少Dlg->XXXX的工作,在线程里面操作主界面的一//些显示,读取数据等工作

for(i=0;i<100000;i++) //这里是我人为模拟 要让它循环这么多次,意为模拟发送这么多次
{
dw = WaitForSingleObject(Dlg->m_CANEvent,10); //让其延迟10ms就输出一个数
if( dw == WAIT_OBJECT_0 ) //收到结束线程信号
{
Dlg->runflag=0; //线程运行标志复位
return 0;
}
if( dw == WAIT_TIMEOUT) //延迟到了,就执行下面的显示数值
{
if(Dlg->uiButton == 1)
{
tmp.Format(" %d ",i);
Dlg->m_count.SetWindowText(tmp); //这个是让其在界面上面显示当前i的数值
} // Dlg->m_count是主界面上面的一个static控件
if(Dlg->uiButton ==2 )
{
tmp.Format(" %d ",i);
Dlg->m_count2.SetWindowText(tmp); //这个是让其在界面上面显示当前i的数值
} // Dlg->m_count是主界面上面的一个static控件
}
}

Dlg->runflag=0; //线程运行标志复位
return 0;
}

void CExample2Dlg::OnButton2() //停止线程的按钮
{
// TODO: Add your control notification handler code here
SetEvent(m_CANEvent);
}


基于上面的代码,我第一次点Button1,那么就正常跑线程MyThread1,跑着跑着,我再点一次Button1,就会执行Button1下面if(runflag==1){…}里面的代码,然后线程MyThread1就自动退出了,可是现在的result=MsgWaitForMultipleObjects(1,m_CANSendThreadHandle,FALSE,INFINITE,QS_ALLINPUT); 返回的result 不会变为result == (WAIT_OBJECT_0) 也就是说,现在就进入死循环,一直在while (PeekMessage(&msg,NULL,0,0,PM_REMOVE))那里循环了,

问题:为什么他在线程结束后 MsgWaitForMultipleObjects不会返回WAIT_OBJECT_0 ?而且我是确定线程是退出了的,在debug窗口里面看到了 我最先以为是MsgWaitForMultipleObjects第二个参数的问题,因为本身线程的那个HANDLE (pCANThreads->m_hThread;)会在线程结束的时候消失,但是我这里是在AfxBeginThread过后就赋值给m_CANSendThreadHandle[0]这个数组了,MsgWaitForMultipleObjects里面参数也是m_CANSendThreadHandle啊,

现在最大的问题就是 为什么MsgWaitForMultipleObjects 检测不到线程退出的信号?

下面是我第二次点击Button1的DEBUG窗口截图;
...全文
393 39 打赏 收藏 转发到动态 举报
写回复
用AI写文章
39 条回复
切换为时间正序
请发表友善的回复…
发表回复
Extre_Lin 2015-01-17
  • 打赏
  • 举报
回复
你好,也是关于MsgWaitForMultipleObjects 这个函数的,想请教你,我QQ:421329605.麻烦你了
Squall001 2014-05-30
  • 打赏
  • 举报
回复
引用 37 楼 schlafenhamster 的回复:
http://www.cnblogs.com/lancidie/archive/2011/04/06/2006748.html
其实这个帖子我已经看过了 它也是用的CreateThread来创建进程,如果用AfxBeginThread的话 随便怎么都是错的。
schlafenhamster 2014-05-19
  • 打赏
  • 举报
回复
而且就从来没经过: // else if( result == WAIT_ABANDONED_0 ) // {// ABANDONED // afxDump << msg.message << " abandoned\n"; // break; // } // else // {// error // afxDump << msg.message << " error\n"; // DWORD dErrCode=GetLastError(); // break; // }
schlafenhamster 2014-05-19
  • 打赏
  • 举报
回复
参考32楼 TRUE 和 FALSE 的 算法 不一样 现在是 FALSE, evevnt 返回是 1 ?. 如果 TRUE 返回是 0. ?
schlafenhamster 2014-05-18
  • 打赏
  • 举报
回复
1. 512 =0x0200 #define WM_MOUSEMOVE 0x0200 2. result 没用了! while (result=PeekMessage(&msg,NULL,0,0,PM_REMOVE)) 不用的消息能不能 不要 ? 那2个 0,0
Squall001 2014-05-18
  • 打赏
  • 举报
回复
引用 4 楼 schlafenhamster 的回复:
就是 PeekMessage 返回值 != 0 ,但 =-1 ??
以下是我源程序的下载地址 http://pan.baidu.com/s/1gdHwkZx 我做了以下追踪改动
			else if( WAIT_OBJECT_0 + 1)
			{
			   while (PeekMessage(&msg,NULL,0,0,PM_NOREMOVE))
			   {	
					TRACE("收到消息,函数返回值为%d,进入消息分发 \n",result);
					TRACE("message里面消息值 %d \n",msg.message);
					TranslateMessage(&msg);
					DispatchMessage(&msg);
			   }
				
			}
DEBUG里面调试信息是 :
收到消息,函数返回值为1,进入消息分发 
message里面消息值 512
schlafenhamster 2014-05-18
  • 打赏
  • 举报
回复
就是 PeekMessage 返回值 != 0 ,但 =-1 ??
schlafenhamster 2014-05-18
  • 打赏
  • 举报
回复
“一直在while (PeekMessage(&msg,NULL,0,0,PM_REMOVE))那里循环了,” 就是 PeekMessage 返回值〉0 afxDump << msg.message << "\n"; 看看他取到了什么?
Squall001 2014-05-18
  • 打赏
  • 举报
回复
引用 1 楼 schlafenhamster 的回复:
PeekMessage(&msg,NULL,0,0,PM_REMOVE) 试试 PeekMessage(&msg,NULL,0,0,PM_NOREMOVE)
很高兴你能回复 不过我试了,如果按照你的方法,消息如果不被取出队列,那么再次点击那个按钮就失败全部死机了。
schlafenhamster 2014-05-18
  • 打赏
  • 举报
回复
PeekMessage(&msg,NULL,0,0,PM_REMOVE) 试试 PeekMessage(&msg,NULL,0,0,PM_NOREMOVE)
Squall001 2014-05-18
  • 打赏
  • 举报
回复
最后给出MSDN上面的解释




MSDN上面根本就没有说用AfxBeginThread 是我一厢情愿的用这个函数的,因为太多的帖子说 ,在MFC里面不要用CreateThread.....
Squall001 2014-05-18
  • 打赏
  • 举报
回复
引用 31 楼 guyuguang8628391 的回复:
MsgWaitForMultipleObjects 这种api尽量少用,用WaitForMultipleObjects


我觉得 还是不要去怀疑这个函数有问题吧

我解决了这个问题

其实很简单 就是在创建线程的时候 用CreateThread才行 因为他返回的那个HANDLE才是有效的, 而我前面用的

pCANThreads=AfxBeginThread(MyThread1,this);
m_CANSendThreadHandle[0]=pCANThreads->m_hThread;

这里的句柄是不对的 在程序运行的时候 DWORD dErrCode=GetLastError(); 有可能得到返回值为6 意思是无效的句柄

下面上正确的代码


void CExample3Dlg::OnButton1()
{
// TODO: Add your control notification handler code here
DWORD result ;
MSG msg ;
if(runflag==1) //如果线程正在运行
{
SetEvent(m_CANEvent); //发出让线程结束
TRACE("发送SetEvent信号,让线程结束 \n");
while (TRUE)
{
//wait for m_hThread to be over,and wait for
//QS_ALLINPUT(Any message is in the queue)
result = MsgWaitForMultipleObjects (1, m_CANSendThreadHandle,FALSE, INFINITE, QS_ALLINPUT);

if(result == WAIT_OBJECT_0)
{
TRACE("MsgWaitForMultipleObjects 返回值 %ld 从WAIT_OBJECT_0消息退出while循环 \n",result);
break; //break the loop
}
else if(result == WAIT_OBJECT_0 + 1)
{
//get the message from Queue
//and dispatch it to specific window
TRACE("MsgWaitForMultipleObjects 返回值 %ld 说明返回WAIT_OBJECT_0 + 1 ,分发消息,继续while循环\n",result);
while (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
{
//afxDump << msg.message << "\n";
TRACE("分发的消息ID=0x%x \n",msg.message);
TranslateMessage(&msg);
DispatchMessage(&msg);
}
continue;
/*
PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
DispatchMessage(&msg);
continue;
*/
}
else if( result == WAIT_ABANDONED_0 )
{
TRACE("MsgWaitForMultipleObjects 返回值 %ld 说明返回WAIT_ABANDONED_0 ,跳出while\n",result);
break;
}
else
{
TRACE("MsgWaitForMultipleObjects 返回值 %ld 从default退出循环 \n",result);
DWORD dErrCode=GetLastError();
TRACE("dErrCode=%ld \n",dErrCode);
break; // unexpected failure
}
}
}
ResetEvent(m_CANEvent); //设置无信号,让线程进入等待超时的工作
uiButton=1; //标记这是按钮响应的函数启动的线程
m_CANSendThreadHandle[0]=CreateThread(NULL,0,MyThread3,this,0,NULL);
runflag=1;
}

DWORD WINAPI CExample3Dlg::MyThread3(LPVOID param)
{
TRACE("MyThread1 Begin\n");
CExample3Dlg *Dlg=(CExample3Dlg *)param;

int i;
CString tmp;
DWORD dw;

for(i=0;i<100000;i++)
{
dw = WaitForSingleObject(Dlg->m_CANEvent,10); //让其延迟10ms就输出一个数
if( dw == WAIT_OBJECT_0 ) //收到结束线程信号
{
Dlg->runflag=0; //线程运行标志复位
TRACE("MyThread1 End 1\n");
return 0; //退出

}
if( dw == WAIT_TIMEOUT) //延迟到了,就执行下面的显示数值
{
if(Dlg->uiButton == 1)
{
tmp.Format(" %d ",i);
Dlg->m_count.SetWindowText(tmp); //这个是让其在界面上面显示当前i的数值
}
if(Dlg->uiButton ==2 )
{
tmp.Format(" %d ",i);
Dlg->m_count2.SetWindowText(tmp); //这个是让其在界面上面显示当前i的数值
}
}
}

Dlg->runflag=0; //线程运行标志复位
TRACE("MyThread1 End\n");
return 0;
}


给出调试的DEBUG截图

schlafenhamster 2014-05-18
  • 打赏
  • 举报
回复
result=MsgWaitForMultipleObjects(1,m_CANSendThreadHandle,TRUE,INFINITE, QS_ALLINPUT | QS_ALLEVENTS | QS_ALLPOSTMESSAGE | QS_SENDMESSAGE); if(result == WAIT_OBJECT_0) {// event afxDump << result << " =WAIT_OBJECT_0\n"; break; } TRUE 和 FALSE 的 算法 不一样.
图灵转世 2014-05-18
  • 打赏
  • 举报
回复
MsgWaitForMultipleObjects 这种api尽量少用,用WaitForMultipleObjects
Squall001 2014-05-18
  • 打赏
  • 举报
回复
引用 29 楼 schlafenhamster 的回复:
17楼的 "开启线程" 有时工作 , 有时不工作 (计数 停)
对啊 就是因为 退出那个while循环根本就不是从result == WAIT_OBJECT_0 这里退出的 所以产生的后果无法预料 线程退出 和开启都要一点时间的 你可以点快点 多点几次 button1 就可以看到实际上开启了多个线程
schlafenhamster 2014-05-18
  • 打赏
  • 举报
回复
17楼的 "开启线程" 有时工作 , 有时不工作 (计数 停)
Squall001 2014-05-18
  • 打赏
  • 举报
回复
引用 27 楼 schlafenhamster 的回复:
"开启线程" 按一下, 老线程关闭,新线程开始(重头计数) 计数是不会停的.
对啊 只要开启了线程 计数器永远就不会停 只会从头计数 你是不是 点快了 计数器就停止了?
schlafenhamster 2014-05-18
  • 打赏
  • 举报
回复
"开启线程" 按一下, 老线程关闭,新线程开始(重头计数) 计数是不会停的.
Squall001 2014-05-18
  • 打赏
  • 举报
回复
引用 25 楼 schlafenhamster 的回复:
"开启线程" 有时工作 , 有时不工作 (计数 停)
什么意思?
加载更多回复(19)

16,471

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧