多线程问题

2012-12-17 11:39:45
目的:主线程等待2个子线程结束。
问题:WaitForMultipleObjects() 总是失败,
主线程:
HANDLE h[2];
CWinThread* pThread1 = AfxBeginThread(DownThread1, this);
h[0]=pThread1->m_hThread;
CWinThread* pThread2 = AfxBeginThread(DownThread2, this);
h[1]=pThread2->m_hThread;

while(true)
{
DWORD ret = WaitForMultipleObjects(2,h,TRUE,150);

if(WAIT_OBJECT_0==ret)
{
break;
}
if(WAIT_FAILED==ret)
{
MessageBox("失败");
}

else //时间到了返回,无信号
{
MSG msg;
PeekMessage(&msg,NULL,0,0,PM_REMOVE);
if(WM_QUIT==msg.message)
return false;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
...全文
241 20 打赏 收藏 转发到动态 举报
写回复
用AI写文章
20 条回复
切换为时间正序
请发表友善的回复…
发表回复
傻X 2012-12-18
  • 打赏
  • 举报
回复
用CEvent内核对象来看看吧 SetEvent来控制
2012-12-18
  • 打赏
  • 举报
回复
引用 8 楼 tiger9991 的回复:
先搞无限等待测试一下。 另外DownThread1和DownThread2里面代码怎么整的?
搞了下无限等待:无论是TRUE还是FALSE,主线程卡在WaitForMultipleObjects(2,h,true或者false,INFINITE);不向下执行了。
zzz_zou 2012-12-18
  • 打赏
  • 举报
回复
你应该是想等待2个线程都退出再做些什么吧,把第三个参数设置为TRUE,只要都等到了就会返回的,我写了个代码,你看看有没参考价值。
unsigned int __stdcall test(void* lparam)
{
	return 1;
}

int main()
{
	uintptr_t test_thread1 = _beginthreadex(NULL, 0, &test, NULL, CREATE_SUSPENDED, NULL);
	uintptr_t test_thread2 = _beginthreadex(NULL, 0, &test, NULL, CREATE_SUSPENDED, NULL);

	HANDLE wait_handle[2] = {0};
	wait_handle[0] = (HANDLE)test_thread1;
	wait_handle[1] = (HANDLE)test_thread2;

	while (true)
	{
		DWORD ret = WaitForMultipleObjects(2, wait_handle, TRUE, 100);

		switch (ret)
		{
		case WAIT_FAILED:
			cout << "failed, error_code:" << GetLastError() << endl;
			break;
		case WAIT_TIMEOUT:
			cout << "timeout" << endl;
			ResumeThread(wait_handle[0]);
			ResumeThread(wait_handle[1]);
			break;
		case WAIT_OBJECT_0:
			cout << "obj 0" << endl;
			CloseHandle(wait_handle[0]);
			break;
		case WAIT_OBJECT_0 + 1:
			cout << "obj 1" << endl;
			CloseHandle(wait_handle[1]);
			break;
		default:
			break;
		}
	}

	return 1;
}
2012-12-18
  • 打赏
  • 举报
回复
引用 7 楼 w_xei 的回复:
也许你的等待还没运行到那里,其他两个线程已经完成了,等待的句柄也许是无效句柄了(因为同优先级线程调度是抢占式的,控制不到),因此要确保两个线程在主线程进入等待前还存在, 另外等待返回出错估计是超时了,这需要三个线程相互调度好
应该是你说的原因,因为我换成:waitfor(...FALSE..)时,有时等到一个,有时都没等到。如何确保子线程在主线程等待前还存在,有什么好的办法?
2012-12-18
  • 打赏
  • 举报
回复
引用 11 楼 zzz_zou 的回复:
失败了getlasterror试试,看结果是多少
GetLastError() 的返回值是0, 意思是:操作成功完成
2012-12-18
  • 打赏
  • 举报
回复
引用 8 楼 tiger9991 的回复:
先搞无限等待测试一下。 另外DownThread1和DownThread2里面代码怎么整的?
我做的是一个下载程序:主线程获得文件大小,然后2个子线程去下载文件的前后2部分,主线程等待子线程结束。子线程代码如下: UINT DownThread1(LPVOID pParam) { CDownLoadDlg *dlg = (CDownLoadDlg*)pParam; CWnd* pwnd = AfxGetMainWnd(); CProgressCtrl* m_progress = (CProgressCtrl*)pwnd->GetDlgItem(IDC_PROGRESS1); struct protoent *ppe; ppe = getprotobyname("tcp"); SOCKET sockClient = socket(PF_INET, SOCK_STREAM, ppe->p_proto); if(sockClient == INVALID_SOCKET) return false; char hostname[56]; memset(hostname,0,sizeof(hostname)); gethostname(hostname,56); CString Host = dlg->m_ini.GetValue(dlg->m_exepath,"Request","Host"); hostent* pHostEnt = gethostbyname(Host.GetBuffer(Host.GetLength())); if(pHostEnt == NULL) return false; Host.ReleaseBuffer(); int nTime = 60000; //由于网络状况等原因,发收不能预期进行,而设置收发时限 setsockopt(sockClient, SOL_SOCKET, SO_SNDTIMEO, (char*)&nTime, sizeof(nTime)); setsockopt(sockClient, SOL_SOCKET, SO_RCVTIMEO, (char*)&nTime, sizeof(nTime)); struct in_addr ip_addr; memcpy(&ip_addr, pHostEnt->h_addr_list[0], 4); struct sockaddr_in destaddr; //服务器的地址 memset((void *)&destaddr, 0, sizeof(destaddr)); destaddr.sin_family = AF_INET; destaddr.sin_port = htons(80); //destaddr.sin_addr.S_un.S_addr=inet_addr("192.168.10.56"); destaddr.sin_addr=ip_addr; while(1) { if(0 == connect(sockClient,(sockaddr*)&destaddr, sizeof(destaddr))) { break; } } CString get = "GET /"+dlg->m_ini.GetValue(dlg->m_exepath,"Request","GET")+" HTTP/1.1\r\n"; CString host= "Host:"+dlg->m_ini.GetValue(dlg->m_exepath,"Request","Host")+"\r\n"; CString accept = "Accept:*/*\r\n"; CString strbytes; strbytes.Format("%d",dlg->m_FileBytes/2); CString range="Range:bytes=0-"+strbytes+"\r\n"; CString user = "User-Agent:Mozilla/4.0 (compatible; MSIE 5.00; Windows 98)\r\n"; CString connection = "Connection:Close\r\n\r\n"; CString request1 = get+host+accept+range+user+connection; char *url1=request1.GetBuffer(request1.GetLength()); request1.ReleaseBuffer(); send(sockClient, url1, strlen(url1), 0); int rcv_bytes = 0; char buf[BUFFSIZE]; memset(buf,0,BUFFSIZE); rcv_bytes = recv(sockClient, buf, BUFFSIZE, 0); //先接收服务器返回的报文定位到\r\n\r\n for(int i=0;i<rcv_bytes-3;i++) { if(buf[i]==13 && buf[i+1]==10 && buf[i+2]==13 && buf[i+3]==10) { EnterCriticalSection(&dlg->m_cs); dlg->m_file.SeekToBegin(); dlg->m_file.Write(buf+i+4, rcv_bytes-i-4); LeaveCriticalSection(&dlg->m_cs); dlg->m_Th1Compelete=rcv_bytes-i-4; m_progress->SetPos((dlg->m_Th1Compelete+dlg->m_Th2Compelete)/1024); break; } } while(1) { rcv_bytes = recv(sockClient, buf, BUFFSIZE, 0); if(rcv_bytes <= 0) break; EnterCriticalSection(&dlg->m_cs); dlg->m_file.Seek(dlg->m_Th1Compelete, CFile::begin); dlg->m_file.Write(buf, rcv_bytes); LeaveCriticalSection(&dlg->m_cs); dlg->m_Th1Compelete+=rcv_bytes; m_progress->SetPos((dlg->m_Th1Compelete+dlg->m_Th2Compelete)/1024); } DWORD exit1; bool flag=GetExitCodeThread(dlg->h[0],&exit1); //AfxEndThread(exit1); return exit1; }
zzz_zou 2012-12-18
  • 打赏
  • 举报
回复
失败了getlasterror试试,看结果是多少
zzz_zou 2012-12-18
  • 打赏
  • 举报
回复
引用 9 楼 lm841984 的回复:
引用 6 楼 zzz_zou 的回复:你是等待失败,我看成超时了。。你看看传入的句柄是否有效。 一般返回值的判断是这样的 case WAIT_FAILED: break; case WAIT_TIMEOUT: break; case WAIT_OBJECT_0: do sth; break; ... 我换成WaitForMultipleO……
如果你改为FALSE了,等到1个就会返回,你的意思是2个线程,等到了1个,再等1个有一定概率会失败吗
2012-12-18
  • 打赏
  • 举报
回复
引用 6 楼 zzz_zou 的回复:
你是等待失败,我看成超时了。。你看看传入的句柄是否有效。 一般返回值的判断是这样的 case WAIT_FAILED:   break; case WAIT_TIMEOUT:   break; case WAIT_OBJECT_0: do sth; break; ...
我换成WaitForMultipleObjects(2,h,FALSE,150); 调试运行多次:有时一个线程退出;有时waitfor()还是失败,失败原因:线程未退出。麻烦你啦!
傻X 2012-12-18
  • 打赏
  • 举报
回复
先搞无限等待测试一下。 另外DownThread1和DownThread2里面代码怎么整的?
w_xei 2012-12-18
  • 打赏
  • 举报
回复
也许你的等待还没运行到那里,其他两个线程已经完成了,等待的句柄也许是无效句柄了(因为同优先级线程调度是抢占式的,控制不到),因此要确保两个线程在主线程进入等待前还存在, 另外等待返回出错估计是超时了,这需要三个线程相互调度好
zzz_zou 2012-12-18
  • 打赏
  • 举报
回复
你是等待失败,我看成超时了。。你看看传入的句柄是否有效。 一般返回值的判断是这样的 case WAIT_FAILED:   break; case WAIT_TIMEOUT:   break; case WAIT_OBJECT_0: do sth; break; ...
ajax_for_spring 2012-12-18
  • 打赏
  • 举报
回复
你用::MessageBox();打印下 WaitForMultipleObjects(2,h,TRUE,150); 的返回值,这样 你就可以基本判断下 错误原因,最好是跟下 看看 调试过程中的 各个函数 的参数的变化这样 才好确定失败原因
zzz_zou 2012-12-18
  • 打赏
  • 举报
回复
引用 19 楼 lm841984 的回复:
引用 15 楼 zzz_zou 的回复:你应该是想等待2个线程都退出再做些什么吧,把第三个参数设置为TRUE,只要都等到了就会返回的,我写了个代码,你看看有没参考价值。 C/C++ code ? 1234567891011121314151617181920212223242526272829303132333435363738394041424……
是这样的,如果仅仅只是主线程等待2个子线程退出的话,直接把第三个参数写为true,然后循环等待就好了,如果等到了,那么说明2个线程都已经退出.我写的那个代码我也测试过了,如果只恢复1个线程,是不会等到的. 当然,如果你做的是下载文件这类应用,那么最好用线程池的方法,不用临时的创建和关闭线程,同步可以通过使用信号量来实现.
2012-12-18
  • 打赏
  • 举报
回复
引用 15 楼 zzz_zou 的回复:
你应该是想等待2个线程都退出再做些什么吧,把第三个参数设置为TRUE,只要都等到了就会返回的,我写了个代码,你看看有没参考价值。 C/C++ code ? 12345678910111213141516171819202122232425262728293031323334353637383940414243 unsigned int __stdcall test(……
非常感谢你的代码。我的主线程等待子线程退出后,关闭主线程之前打开的文件。主线程打开,关闭文件,2个子线程下载并写入文件。兄才可有更好的做法,不吝赐教。
2012-12-18
  • 打赏
  • 举报
回复
引用 17 楼 tiger9991 的回复:
用CEvent内核对象来看看吧 SetEvent来控制
用事件内核对象来控制线程同步吗??我代码中用的是关键代码段控制的
zzz_zou 2012-12-17
  • 打赏
  • 举报
回复
等待失败,说明你子线程未退出,你可以看看子线程在干啥
2012-12-17
  • 打赏
  • 举报
回复
2012-12-17
  • 打赏
  • 举报
回复
引用 1 楼 zzz_zou 的回复:
等待失败,说明你子线程未退出,你可以看看子线程在干啥
2个子线程都退出了,该干的活都干完了。WaitForMultipleObjects()还是失败

15,471

社区成员

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

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