线程退出

shengtwotwo 2016-11-03 08:46:20
    ::PostThreadMessage(dwDrawThreadID,WM_QUIT,0,0);
WaitForSingleObject(m_hDrawThread,3000);


我在主线程创造事件,然后往子线程发送消息触发事件,主线程等待事件,然后却发现子线程收不到消息。
发送结束消息,然后主线程等待子线程结束,也是有问题。
单独发消息,不设置等待事件又没问题。
难道是因为我在主线程等待事件的原因?
怎么解决这种还有工作线程在进行的情况,程序却要退出的。
...全文
479 25 打赏 收藏 转发到动态 举报
写回复
用AI写文章
25 条回复
切换为时间正序
请发表友善的回复…
发表回复
Saleayas 2016-11-04
  • 打赏
  • 举报
回复
检测Post 的返回值。 同时 Post 要求接收的线程已经建立消息队列。 // MSDN Create an event object, then create the thread. Use the WaitForSingleObject function to wait for the event to be set to the signaled state before calling PostThreadMessage. In the thread to which the message will be posted, call PeekMessage as shown here to force the system to create the message queue. PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE) Set the event, to indicate that the thread is ready to receive posted messages.
BeanJoy 2016-11-04
  • 打赏
  • 举报
回复
你有把PostThreadMessage()的返回和GetLastError()的值打出来吗?看看PostThreadMessage()到底执行成功没有,不要想当然一定会成功,有时候往往就会卡在这些地方。
BeanJoy 2016-11-04
  • 打赏
  • 举报
回复
引用 22 楼 u014770199 的回复:
[quote=引用 21 楼 BeanJoy 的回复:] [quote=引用 20 楼 u014770199 的回复:] [quote=引用 19 楼 BeanJoy 的回复:] 问题明了了,你这个例子里PostThreadMessage会失败,LastErrorCode为1444(无效的线程标识符符。),因为刚CreateThread,就调用PostThreadMessage,新线程还没有消息队列,PostThreadMessage就会Post失败。 而要新线程调用GetMessage就会创建一个消息队列,但是在执行GetMessage前,主线程就已经调用了PostThreadMessage,而且失败了。 你这个例子,简单的改法就是在PostThreadMessage前加个Sleep,保证在PostThreadMessage前,新线程的GetMessage一定执行了。 当然也可以参考PostThreadMessage和GetMessage里的方法,主线程和新线程使用事件同步,保证新线程已有了消息队列再PostThreadMessage。
虽然我知道你说的不对,因为即使我消息队列创建也还是收不到,不过我改代码了,采取应答模式,直接消息对话。 但是sleep应该是能解决问题得,就是post后加sleep等待线程收到之后再wait等待,这应该是可以的。不过还是谢谢了。而且主线程wait也卡界面。虽然是关闭的时候,但是还是不让它卡好。[/quote] 看你这么说,就知道你没有仔细看我的回复,或者没有理解到。还是给个简单的例子吧,如下。下面的代码跑起来,子线程我主线程都会卡,你在CloseThread()中的DWORD dwLastError = GetLastError();打个断点,然后测试,你会发现PostThreadMessage()的返回值bRet为FALSE,而dwLastError也为1444,因为子线程还没来得及执行GetMessage()创建消息队列。 然后你把CloseThread()中Sleep(1000);前的注释放开,再跑一下试试,你就会发现程序已经能正常工作了,因为主线程中Sleep(1000)等待,子线程就有足够的时间执行GetMessage()来创建一个消息队列,然后主线程再执行PostThreadMessage()就能正确的发送一个消息到子线程的消息队列中。

#include "stdafx.h"
#include <windows.h>

#pragma comment(lib, "User32.lib")

HANDLE m_hDrawThread = NULL;
DWORD dwDrawThreadID = 0;

DWORD WINAPI MyThread(LPVOID lpParam) 
{ 
	MSG msg;
	while (GetMessage(&msg, 0, 0, 0))
	{
		TranslateMessage(&msg);
		if (!msg.hwnd)
		{
			int i = 0;
		}
			//OnThreadMessage(msg.message, msg.wParam, msg.lParam);
		DispatchMessage(&msg);
	}

	return 0; 
} 

void CloseThread()
{
	// Sleep(1000);
	BOOL bRet = ::PostThreadMessage(dwDrawThreadID,WM_QUIT,0,0);
	DWORD dwLastError = GetLastError();
	//WaitForSingleObject(m_hDrawThread,3000);
	WaitForSingleObject(m_hDrawThread,INFINITE);
}

int main(int argc, char **argv)
{
	m_hDrawThread = CreateThread( 
		NULL,              // default security attributes
		0,                 // use default stack size  
		MyThread,          // thread function 
		NULL,             // argument to thread function 
		0,                 // use default creation flags 
		&dwDrawThreadID);   // returns the thread identifier 

	CloseThread();

	return 0;
}
[/quote] 事实是我消息队列之前就创建了,不知道你说的消息队列是什么意思。我之前程序有其他消息操作正常接收,就是关闭的时候没法接收,而且。你这个主线程一直等待子线程关闭,最后不知道你是怎么关闭的,至于你说的卡,就是因为子线程未关闭,主线程一直等待,wait设置超时5秒,只会卡5秒。如果你说真的消息成功发送接收处理,那么子线程立即退出,主线程根本感觉不到等待。 而且你觉得是消息队列的问题,那你可以之前发其他的消息测试看看,直到正确后你再WM_Qiut和Wait。然后看看子线程是怎么退出的。 while (GetMessage(&msg, 0, 0, 0)) { TranslateMessage(&msg); if (!msg.hwnd) { int i = 0; } //OnThreadMessage(msg.message, msg.wParam, msg.lParam); DispatchMessage(&msg); } //afxmessagebox打印。你在这里打印东西就知道成功结束没有,还是最后选择强杀。[/quote] 一个线程一个消息队列,不要认为有其他线程能成功接收消息,这个子线程就有消息队列。 当没有消息时,子线程会一直卡在while (GetMessage(&msg, 0, 0, 0))这里,而当接收到WM_QUIT 消息时,GetMessage()会返回0(接收到其他消息返回非0),就退出while循环,子线程就会结束,主线程中的Wait也就能正常返回,主线程正常结束。 所以,加上afxmessagebox,也是一定会弹出messagebox的。
shengtwotwo 2016-11-04
  • 打赏
  • 举报
回复
引用 21 楼 BeanJoy 的回复:
[quote=引用 20 楼 u014770199 的回复:] [quote=引用 19 楼 BeanJoy 的回复:] 问题明了了,你这个例子里PostThreadMessage会失败,LastErrorCode为1444(无效的线程标识符符。),因为刚CreateThread,就调用PostThreadMessage,新线程还没有消息队列,PostThreadMessage就会Post失败。 而要新线程调用GetMessage就会创建一个消息队列,但是在执行GetMessage前,主线程就已经调用了PostThreadMessage,而且失败了。 你这个例子,简单的改法就是在PostThreadMessage前加个Sleep,保证在PostThreadMessage前,新线程的GetMessage一定执行了。 当然也可以参考PostThreadMessage和GetMessage里的方法,主线程和新线程使用事件同步,保证新线程已有了消息队列再PostThreadMessage。
虽然我知道你说的不对,因为即使我消息队列创建也还是收不到,不过我改代码了,采取应答模式,直接消息对话。 但是sleep应该是能解决问题得,就是post后加sleep等待线程收到之后再wait等待,这应该是可以的。不过还是谢谢了。而且主线程wait也卡界面。虽然是关闭的时候,但是还是不让它卡好。[/quote] 看你这么说,就知道你没有仔细看我的回复,或者没有理解到。还是给个简单的例子吧,如下。下面的代码跑起来,子线程我主线程都会卡,你在CloseThread()中的DWORD dwLastError = GetLastError();打个断点,然后测试,你会发现PostThreadMessage()的返回值bRet为FALSE,而dwLastError也为1444,因为子线程还没来得及执行GetMessage()创建消息队列。 然后你把CloseThread()中Sleep(1000);前的注释放开,再跑一下试试,你就会发现程序已经能正常工作了,因为主线程中Sleep(1000)等待,子线程就有足够的时间执行GetMessage()来创建一个消息队列,然后主线程再执行PostThreadMessage()就能正确的发送一个消息到子线程的消息队列中。

#include "stdafx.h"
#include <windows.h>

#pragma comment(lib, "User32.lib")

HANDLE m_hDrawThread = NULL;
DWORD dwDrawThreadID = 0;

DWORD WINAPI MyThread(LPVOID lpParam) 
{ 
	MSG msg;
	while (GetMessage(&msg, 0, 0, 0))
	{
		TranslateMessage(&msg);
		if (!msg.hwnd)
		{
			int i = 0;
		}
			//OnThreadMessage(msg.message, msg.wParam, msg.lParam);
		DispatchMessage(&msg);
	}

	return 0; 
} 

void CloseThread()
{
	// Sleep(1000);
	BOOL bRet = ::PostThreadMessage(dwDrawThreadID,WM_QUIT,0,0);
	DWORD dwLastError = GetLastError();
	//WaitForSingleObject(m_hDrawThread,3000);
	WaitForSingleObject(m_hDrawThread,INFINITE);
}

int main(int argc, char **argv)
{
	m_hDrawThread = CreateThread( 
		NULL,              // default security attributes
		0,                 // use default stack size  
		MyThread,          // thread function 
		NULL,             // argument to thread function 
		0,                 // use default creation flags 
		&dwDrawThreadID);   // returns the thread identifier 

	CloseThread();

	return 0;
}
[/quote] 事实是我消息队列之前就创建了,不知道你说的消息队列是什么意思。我之前程序有其他消息操作正常接收,就是关闭的时候没法接收,而且。你这个主线程一直等待子线程关闭,最后不知道你是怎么关闭的,至于你说的卡,就是因为子线程未关闭,主线程一直等待,wait设置超时5秒,只会卡5秒。如果你说真的消息成功发送接收处理,那么子线程立即退出,主线程根本感觉不到等待。 而且你觉得是消息队列的问题,那你可以之前发其他的消息测试看看,直到正确后你再WM_Qiut和Wait。然后看看子线程是怎么退出的。 while (GetMessage(&msg, 0, 0, 0)) { TranslateMessage(&msg); if (!msg.hwnd) { int i = 0; } //OnThreadMessage(msg.message, msg.wParam, msg.lParam); DispatchMessage(&msg); } //afxmessagebox打印。你在这里打印东西就知道成功结束没有,还是最后选择强杀。
BeanJoy 2016-11-04
  • 打赏
  • 举报
回复
引用 20 楼 u014770199 的回复:
[quote=引用 19 楼 BeanJoy 的回复:] 问题明了了,你这个例子里PostThreadMessage会失败,LastErrorCode为1444(无效的线程标识符符。),因为刚CreateThread,就调用PostThreadMessage,新线程还没有消息队列,PostThreadMessage就会Post失败。 而要新线程调用GetMessage就会创建一个消息队列,但是在执行GetMessage前,主线程就已经调用了PostThreadMessage,而且失败了。 你这个例子,简单的改法就是在PostThreadMessage前加个Sleep,保证在PostThreadMessage前,新线程的GetMessage一定执行了。 当然也可以参考PostThreadMessage和GetMessage里的方法,主线程和新线程使用事件同步,保证新线程已有了消息队列再PostThreadMessage。
虽然我知道你说的不对,因为即使我消息队列创建也还是收不到,不过我改代码了,采取应答模式,直接消息对话。 但是sleep应该是能解决问题得,就是post后加sleep等待线程收到之后再wait等待,这应该是可以的。不过还是谢谢了。而且主线程wait也卡界面。虽然是关闭的时候,但是还是不让它卡好。[/quote] 看你这么说,就知道你没有仔细看我的回复,或者没有理解到。还是给个简单的例子吧,如下。下面的代码跑起来,子线程我主线程都会卡,你在CloseThread()中的DWORD dwLastError = GetLastError();打个断点,然后测试,你会发现PostThreadMessage()的返回值bRet为FALSE,而dwLastError也为1444,因为子线程还没来得及执行GetMessage()创建消息队列。 然后你把CloseThread()中Sleep(1000);前的注释放开,再跑一下试试,你就会发现程序已经能正常工作了,因为主线程中Sleep(1000)等待,子线程就有足够的时间执行GetMessage()来创建一个消息队列,然后主线程再执行PostThreadMessage()就能正确的发送一个消息到子线程的消息队列中。

#include "stdafx.h"
#include <windows.h>

#pragma comment(lib, "User32.lib")

HANDLE m_hDrawThread = NULL;
DWORD dwDrawThreadID = 0;

DWORD WINAPI MyThread(LPVOID lpParam) 
{ 
	MSG msg;
	while (GetMessage(&msg, 0, 0, 0))
	{
		TranslateMessage(&msg);
		if (!msg.hwnd)
		{
			int i = 0;
		}
			//OnThreadMessage(msg.message, msg.wParam, msg.lParam);
		DispatchMessage(&msg);
	}

	return 0; 
} 

void CloseThread()
{
	// Sleep(1000);
	BOOL bRet = ::PostThreadMessage(dwDrawThreadID,WM_QUIT,0,0);
	DWORD dwLastError = GetLastError();
	//WaitForSingleObject(m_hDrawThread,3000);
	WaitForSingleObject(m_hDrawThread,INFINITE);
}

int main(int argc, char **argv)
{
	m_hDrawThread = CreateThread( 
		NULL,              // default security attributes
		0,                 // use default stack size  
		MyThread,          // thread function 
		NULL,             // argument to thread function 
		0,                 // use default creation flags 
		&dwDrawThreadID);   // returns the thread identifier 

	CloseThread();

	return 0;
}
shengtwotwo 2016-11-04
  • 打赏
  • 举报
回复
引用 19 楼 BeanJoy 的回复:
问题明了了,你这个例子里PostThreadMessage会失败,LastErrorCode为1444(无效的线程标识符符。),因为刚CreateThread,就调用PostThreadMessage,新线程还没有消息队列,PostThreadMessage就会Post失败。 而要新线程调用GetMessage就会创建一个消息队列,但是在执行GetMessage前,主线程就已经调用了PostThreadMessage,而且失败了。 你这个例子,简单的改法就是在PostThreadMessage前加个Sleep,保证在PostThreadMessage前,新线程的GetMessage一定执行了。 当然也可以参考PostThreadMessage和GetMessage里的方法,主线程和新线程使用事件同步,保证新线程已有了消息队列再PostThreadMessage。
虽然我知道你说的不对,因为即使我消息队列创建也还是收不到,不过我改代码了,采取应答模式,直接消息对话。 但是sleep应该是能解决问题得,就是post后加sleep等待线程收到之后再wait等待,这应该是可以的。不过还是谢谢了。而且主线程wait也卡界面。虽然是关闭的时候,但是还是不让它卡好。
BeanJoy 2016-11-03
  • 打赏
  • 举报
回复
引用 6 楼 lx624909677 的回复:
[quote=引用 5 楼 BeanJoy 的回复:] 你怎么确认子线程没有收到消息? 是根据主线程中WaitForSingleObject有没有返回确认的? 在子线程处理消息的开头就打印日志来确认下子线程有没有收到消息。把代码精简发上来看看,或许是子线程收到消息了,但是因为代码问题,导致事件没有被SetEvent和子线程没有退出,所以主线程WaitForSingleObjec事件和WaitForSingleObjec子线程句柄都不返回。
发消息用SendMessage发送就一定会收到[/quote] 楼主用的是Post,Post过去,子线程可以卡在其他地方没有处理这个消息也是可能的。
赵4老师 2016-11-03
  • 打赏
  • 举报
回复
《Windows核心编程》
lx624909677 2016-11-03
  • 打赏
  • 举报
回复
引用 5 楼 BeanJoy 的回复:
你怎么确认子线程没有收到消息? 是根据主线程中WaitForSingleObject有没有返回确认的? 在子线程处理消息的开头就打印日志来确认下子线程有没有收到消息。把代码精简发上来看看,或许是子线程收到消息了,但是因为代码问题,导致事件没有被SetEvent和子线程没有退出,所以主线程WaitForSingleObjec事件和WaitForSingleObjec子线程句柄都不返回。
发消息用SendMessage发送就一定会收到
BeanJoy 2016-11-03
  • 打赏
  • 举报
回复
你怎么确认子线程没有收到消息? 是根据主线程中WaitForSingleObject有没有返回确认的? 在子线程处理消息的开头就打印日志来确认下子线程有没有收到消息。把代码精简发上来看看,或许是子线程收到消息了,但是因为代码问题,导致事件没有被SetEvent和子线程没有退出,所以主线程WaitForSingleObjec事件和WaitForSingleObjec子线程句柄都不返回。
zgl7903 2016-11-03
  • 打赏
  • 举报
回复
WM_QUIT 会导致消息泵循环结束 发送 WM_DESTROY 等消息, 让窗口自己退出
shengtwotwo 2016-11-03
  • 打赏
  • 举报
回复
引用 2 楼 chengbar 的回复:
子线程的消息循环是否有问题?
引用 2 楼 chengbar 的回复:
子线程的消息循环是否有问题?
没有,如果去掉等待,只发消息,完全没问题,发消息一等待,子线程就收不到了。
sevancheng 2016-11-03
  • 打赏
  • 举报
回复
子线程的消息循环是否有问题?
三岁、就很帅 2016-11-03
  • 打赏
  • 举报
回复
发消息去挂起线程 然后退出
BeanJoy 2016-11-03
  • 打赏
  • 举报
回复
问题明了了,你这个例子里PostThreadMessage会失败,LastErrorCode为1444(无效的线程标识符符。),因为刚CreateThread,就调用PostThreadMessage,新线程还没有消息队列,PostThreadMessage就会Post失败。 而要新线程调用GetMessage就会创建一个消息队列,但是在执行GetMessage前,主线程就已经调用了PostThreadMessage,而且失败了。 你这个例子,简单的改法就是在PostThreadMessage前加个Sleep,保证在PostThreadMessage前,新线程的GetMessage一定执行了。 当然也可以参考PostThreadMessage和GetMessage里的方法,主线程和新线程使用事件同步,保证新线程已有了消息队列再PostThreadMessage。
shengtwotwo 2016-11-03
  • 打赏
  • 举报
回复
引用 17 楼 BeanJoy 的回复:
要是可以,直接把完整代码帖上来分析下。
主线程 void CloseThread() { ::PostThreadMessage(dwDrawThreadID,WM_QUIT,0,0); WaitForSingleObject(m_hDrawThread,3000); } 子线程,消息循环。 ThreadRun { while (GetMessage(&msg, 0, 0, 0)) { TranslateMessage(&msg); if (!msg.hwnd) OnThreadMessage(msg.message, msg.wParam, msg.lParam); DispatchMessage(&msg); } //。。。。 } 懂了吧。主线程单独发消息 void CloseThread() { ::PostThreadMessage(dwDrawThreadID,WM_QUIT,0,0); } 就这。
BeanJoy 2016-11-03
  • 打赏
  • 举报
回复
要是可以,直接把完整代码帖上来分析下。
BeanJoy 2016-11-03
  • 打赏
  • 举报
回复
我看着还是有点混乱,你是说主线程不调用WaitForSingleObject,主线程就可以退出?
shengtwotwo 2016-11-03
  • 打赏
  • 举报
回复
引用 13 楼 VisualEleven 的回复:
程序是不是死锁了??


::PostThreadMessage(dwDrawThreadID,WM_QUIT,0,0);
WaitForSingleObject(m_hDrawThread,3000);

我就单独测试,子线程退出这个,应该不会造成死锁。设置为3秒,5秒结果最后都是强杀。反正很短的时间内没退出。
单独 ::PostThreadMessage(dwDrawThreadID,WM_QUIT,0,0);
就没花时间就看到线程结束了。上面有说循环消息线程,结束我打印东西了的。所以知道。
shengtwotwo 2016-11-03
  • 打赏
  • 举报
回复
引用 11 楼 lx624909677 的回复:
[quote=引用 8 楼 BeanJoy 的回复:] [quote=引用 6 楼 lx624909677 的回复:] [quote=引用 5 楼 BeanJoy 的回复:] 你怎么确认子线程没有收到消息? 是根据主线程中WaitForSingleObject有没有返回确认的? 在子线程处理消息的开头就打印日志来确认下子线程有没有收到消息。把代码精简发上来看看,或许是子线程收到消息了,但是因为代码问题,导致事件没有被SetEvent和子线程没有退出,所以主线程WaitForSingleObjec事件和WaitForSingleObjec子线程句柄都不返回。
发消息用SendMessage发送就一定会收到[/quote] 楼主用的是Post,Post过去,子线程可以卡在其他地方没有处理这个消息也是可能的。[/quote] post过去了,不一定会收到,send的话,会在消息队列中,不会收不到,最多是晚点收到[/quote] 没有窗口,只是一个消息循环的线程。sendmessage不了。还有如果是晚点收到,那么等待超时,也是强杀,那也没意义,而且,消息队列中肯定没有其余消息了,不会说延迟处理的问题。
加载更多回复(5)

15,472

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 进程/线程/DLL
社区管理员
  • 进程/线程/DLL社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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