C++ 如果立即关闭句柄,则RegisterWaitForSingleObject有时会崩溃
我有时会在RegisterWaitForSingleObject中遇到崩溃(10分之一)。看起来,尽管RegisterWaitForSingleObject返回,但内部线程池尚未就绪C++ 如果立即关闭句柄,则RegisterWaitForSingleObject有时会崩溃,c++,winapi,C++,Winapi,我有时会在RegisterWaitForSingleObject中遇到崩溃(10分之一)。看起来,尽管RegisterWaitForSingleObject返回,但内部线程池尚未就绪 HANDLE processHandle = OpenProcess (PROCESS_ALL_ACCESS, FALSE, processID); // CRASH IN INTERNAL SOMETIMES RegisterWaitForSingleObject (&hWaitForChild_,pr
HANDLE processHandle = OpenProcess (PROCESS_ALL_ACCESS, FALSE, processID);
// CRASH IN INTERNAL SOMETIMES
RegisterWaitForSingleObject (&hWaitForChild_,processHandle,OnChildProcessExit, 0,INFINITE,WT_EXECUTEONLYONCE);
// If I sleep here, then it seems ok.
//std::this_thread::sleep_for (std::chrono::milliseconds (10));
CloseHandle (processHandle);
我可以在这里用一个简单的例子来复制这个。10次中有1次,它会崩溃。我应该如何在不诉诸睡眠黑客的情况下正确地同步它
根据您的代码spinet:
// THIS CRASHS HERE SOMETIMES
if (! RegisterWaitForSingleObject (
&hWaitForChild_
,processHandle
, OnChildProcessExit
, 0 //this
, INFINITE
, WT_EXECUTEONLYONCE))
{
LogDebug ("RegisterWaitForSingleObject failed");
}
// If this is enabled, then it won't crash
//std::this_thread::sleep_for (std::chrono::milliseconds (10));
if (! CloseHandle (processHandle)) // !!!
LogDebug ("RegisterWaitForSingleObject Closehandle failed");
因此,在调用此句柄的RegisterWaitForSingleObject
之后,您将关闭processHandle
。但是,如果阅读以下内容:
如果在等待仍处于挂起状态时关闭此句柄,则
函数的行为未定义
如果看得更深入-尝试了解-如何在内部工作RegisterWaitForSingleObject
?它将processHandle
传递给某个工作线程。这个线程开始等待这个句柄。但这是(将句柄传递给另一个线程)异步操作——例如,可以在内部以该句柄作为参数启动新线程,也可以通过某个信号将其传递给已经存在的工作线程。但无论如何,工作线程得到了这个句柄,并开始等待一些以后。从另一侧-您只需在RegisterWaitForSingleObject
返回控件之后关闭processHandle
。所以在这里,race(第一个)或worked thread begin(工作线程开始)等待句柄(在本例中,所有线程都将工作),或者关闭此句柄。如果您先关闭此句柄-工作线程将尝试等待已经无效的句柄并引发异常-状态\u THREADPOOL\u handle\u exception
// If this is enabled, then it won't crash
//std::this_thread::sleep_for (std::chrono::milliseconds (10));
当然,通过睡眠,您可以让工作线程有时间开始等待句柄。在这种情况下,他开始等待,然后再关闭手柄
解决方案-在不调用WAITORTIMERCALLBACK回调之前,不能关闭句柄。您需要分配一些上下文,其中放置processHandle
,并将该上下文传递给RegisterWaitForSingleObject
。当您调用回调时,您得到了指向上下文的指针,返回到这里并关闭句柄
还要注意的是,您不需要为子进程打开单独的第二个句柄,但可以使用CreateProcess
根据您的代码spinet返回的进程句柄:
// THIS CRASHS HERE SOMETIMES
if (! RegisterWaitForSingleObject (
&hWaitForChild_
,processHandle
, OnChildProcessExit
, 0 //this
, INFINITE
, WT_EXECUTEONLYONCE))
{
LogDebug ("RegisterWaitForSingleObject failed");
}
// If this is enabled, then it won't crash
//std::this_thread::sleep_for (std::chrono::milliseconds (10));
if (! CloseHandle (processHandle)) // !!!
LogDebug ("RegisterWaitForSingleObject Closehandle failed");
因此,在调用此句柄的RegisterWaitForSingleObject
之后,您将关闭processHandle
。但是,如果阅读以下内容:
如果在等待仍处于挂起状态时关闭此句柄,则
函数的行为未定义
如果看得更深入-尝试了解-如何在内部工作RegisterWaitForSingleObject
?它将processHandle
传递给某个工作线程。这个线程开始等待这个句柄。但这是(将句柄传递给另一个线程)异步操作——例如,可以在内部以该句柄作为参数启动新线程,也可以通过某个信号将其传递给已经存在的工作线程。但无论如何,工作线程得到了这个句柄,并开始等待一些以后。从另一侧-您只需在RegisterWaitForSingleObject
返回控件之后关闭processHandle
。所以在这里,race(第一个)或worked thread begin(工作线程开始)等待句柄(在本例中,所有线程都将工作),或者关闭此句柄。如果您先关闭此句柄-工作线程将尝试等待已经无效的句柄并引发异常-状态\u THREADPOOL\u handle\u exception
// If this is enabled, then it won't crash
//std::this_thread::sleep_for (std::chrono::milliseconds (10));
当然,通过睡眠,您可以让工作线程有时间开始等待句柄。在这种情况下,他开始等待,然后再关闭手柄
解决方案-在不调用WAITORTIMERCALLBACK回调之前,不能关闭句柄。您需要分配一些上下文,其中放置processHandle
,并将该上下文传递给RegisterWaitForSingleObject
。当您调用回调时,您得到了指向上下文的指针,返回到这里并关闭句柄
还要注意的是,您不需要为子进程打开单独的第二个句柄,但可以使用CreateProcess
返回的进程句柄。好的,我通过保留句柄直到调用Unregisterwait来解决这个问题。情况似乎稳定。多亏了这些答案。好的,我设法解决了这个问题,在我调用Unregisterwait之前一直保持手柄不变。情况似乎稳定。感谢您的回答。我遇到了与您相同的问题,即在Visual Studio中调试时发生异常。我试了很多次,终于找到了原因。如果关闭新创建的进程的句柄,程序将崩溃。我尝试关闭回调函数中的句柄,它工作得非常好,如下所示:
typedef struct {
LPTSTR pszCmdLine;
HANDLE hEvent;
} THREAD_PARAM;
typedef struct {
TCHAR szCmdLine[1024];
HANDLE hWaitObject;
DWORD dwProcessId;
HANDLE hProcess;
DWORD dwThreadId;
HANDLE hThread;
} OBJECT_PARAM;
static void CALLBACK WaitObjectCallback(LPVOID lpParam, BOOLEAN TimerOrWaitFired)
{
OBJECT_PARAM *pobp = static_cast<OBJECT_PARAM *>(lpParam);
TCHAR szInfo[1024] = { 0 };
DWORD dwExitCode = 0;
GetExitCodeProcess(pobp->hProcess, &dwExitCode);
wnsprintf(szInfo, ARRAYSIZE(szInfo), _T("process %u [%s] exit: %u\n"), pobp->dwProcessId, pobp->szCmdLine, dwExitCode);
OutputDebugString(szInfo);
//
// unregister the wait object handle and close the process handle finally
//
UnregisterWait(pobp->hWaitObject);
CloseHandle(pobp->hProcess);
CloseHandle(pobp->hThread);
GlobalFree(lpParam);
}
static DWORD CALLBACK ThreadFunction(LPVOID lpParam)
{
THREAD_PARAM *pthp = static_cast<THREAD_PARAM *>(lpParam);
STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi = { 0 };
BOOL bResult;
bResult = CreateProcess(nullptr, pthp->pszCmdLine, nullptr, nullptr, FALSE, 0, nullptr, nullptr, &si, &pi);
if (bResult)
{
OBJECT_PARAM *pobp = static_cast<OBJECT_PARAM *>(GlobalAlloc(GPTR, sizeof(OBJECT_PARAM)));
// make copy of the command line and other informations of the newly created process
lstrcpyn(pobp->szCmdLine, pthp->pszCmdLine, ARRAYSIZE(pobp->szCmdLine));
pobp->dwProcessId = pi.dwProcessId;
pobp->hProcess = pi.hProcess;
pobp->dwThreadId = pi.dwThreadId;
pobp->hThread = pi.hThread;
bResult = RegisterWaitForSingleObject(&pobp->hWaitObject, pi.hProcess, WaitObjectCallback, pobp, INFINITE, WT_EXECUTEONLYONCE);
// once it failed...
if (!bResult)
{
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
}
// Notify the thread creator that the process is created successfully
SetEvent(pthp->hEvent);
return 0;
}
typedef结构{
LPTSTR pszCmdLine;
处理hEvent;
}螺纹参数;
类型定义结构{
TCHAR szCmdLine[1024];
处理hWaitObject;
DWORD dwProcessId;
处理hProcess;
德沃德·德维德;
处理hThread;
}对象参数;
静态无效回调WaitObjectCallback(LPVOID lpParam,布尔TimerOrWaitFired)
{
OBJECT_PARAM*pobp=静态_cast(lpParam);
TCHAR szInfo[1024]={0};
DWORD dwExitCode=0;
GetExitCode(pobp->hProcess和dwExitCode);
wnsprintf(szInfo,ARRAYSIZE(szInfo),_T(“进程%u[%s]出口:%u\n”)、pobp->dwProcessId、pobp->szCmdLine、dwExitCode);
OutputDebugString(szInfo);
//
//取消注册等待对象句柄并最终关闭进程句柄
//
取消注册等待(pobp->hWaitObject);
CloseHandle(pobp->HPProcess);
CloseHandle(pobp->hThread);
GlobalFree(lpParam);
}
静态DWORD回调线程函数(LPVOID lpParam)
{
螺纹参数*pthp=静态铸造(lpParam);
STARTUPINFO si={sizeof(si)};
进程信息pi={0};
布尔·布雷苏特;
bResult=CreateProcess(nullptr,pthp->pszCmdLine,nullptr,nullptr,FALSE,0,nullptr,nullptr,&si,&pi);
if(bResult)
{
对象参数*pobp=静态强制转换(全局)