gpt4 book ai didi

c++ - TerminateThread() with CloseHandle() on thread which uses only stack plain variables (without alloc) 泄漏内存?

转载 作者:太空宇宙 更新时间:2023-11-04 06:11:40 25 4
gpt4 key购买 nike

我创建了创建两个线程的简单测试;第一个 (WorkerThreadFun) 执行无限循环,第二个 (WorkerGuardThreadFun) 以小超时终止它。

要终止的线程似乎没有进行显式分配(至少在 WorkerThreadFun 内部)并且只使用普通 C 类型的堆栈变量,所以我希望堆栈将被 TerminateThread< 释放/em>() 与 CloseHandle()。

由于某种原因,此测试会泄漏我的 Win7 上的内存。

堆分配不平衡在哪里?

#include <windows.h>
#include <synchapi.h>
#include <assert.h>
#include <stdio.h>

#define STK_SIZE 4097

typedef enum
{
GRD_IDLE,
GRD_READY,
GRD_TASKSTARTING,
GRD_TASKWAITING
} GuardThreadState;

typedef struct
{
HANDLE mHworkerThread;
HANDLE mHworkerGroupThread;

volatile int mIsWorkerStarted;

GuardThreadState mGuardThreadState;

CRITICAL_SECTION mLock;
CONDITION_VARIABLE mThreadReadyCond;
CONDITION_VARIABLE mStartTaskCond;
CONDITION_VARIABLE mTaskFinishedCond;
} WorkerThreadHolder;

/*
typedef VOID(WINAPI *PRtlFreeUserThreadStack)(HANDLE hProcess, HANDLE hThread);
static PRtlFreeUserThreadStack RtlFreeUserThreadStack = NULL;
*/

DWORD WINAPI WorkerThreadFun(_In_ LPVOID p);
DWORD WINAPI WorkerGuardThreadFun(_In_ LPVOID p);

void Start(WorkerThreadHolder *workerThreadHolderPtr);
void ExecuteTask(WorkerThreadHolder *workerThreadHolderPtr);

/*----------------------------------------------------------------------------*/

DWORD WINAPI WorkerThreadFun(_In_ LPVOID p)
{
/* use stack variables only in this thread in hope the stack will be deallocated by TerminateThread() */
WorkerThreadHolder *workerThreadHolderPtr = (WorkerThreadHolder *)p;
volatile int i;

workerThreadHolderPtr->mIsWorkerStarted = 1;
/*WakeAllConditionVariable(&workerThreadHolderPtr->mThreadReadyCond);*/

/* do nothing for infinite long time */
for(i = 0;; ++i)
i = i;

/*WakeAllConditionVariable(&workerThreadHolderPtr->mTaskFinishedCond);*/

return 0;
}

DWORD WINAPI WorkerGuardThreadFun(_In_ LPVOID p)
{
const DWORD taskExecutionTimeoutInMillisec = 1;
WorkerThreadHolder *workerThreadHolderPtr = (WorkerThreadHolder *)p;

EnterCriticalSection(&workerThreadHolderPtr->mLock);

workerThreadHolderPtr->mGuardThreadState = GRD_READY;

WakeAllConditionVariable(&workerThreadHolderPtr->mThreadReadyCond);

for (;;)
{
for (;;)
{
SleepConditionVariableCS(
&workerThreadHolderPtr->mStartTaskCond,
&workerThreadHolderPtr->mLock,
INFINITE);

if (workerThreadHolderPtr->mGuardThreadState == GRD_TASKSTARTING)
break;
}

workerThreadHolderPtr->mGuardThreadState = GRD_TASKWAITING;

{
BOOL isTaskFinishedOk = FALSE;

for (;;)
{
isTaskFinishedOk =
SleepConditionVariableCS(
&workerThreadHolderPtr->mTaskFinishedCond,
&workerThreadHolderPtr->mLock,
taskExecutionTimeoutInMillisec);

if (!isTaskFinishedOk)
break;
}

if (isTaskFinishedOk)
{
/* never happens in this test */
}
else
{
BOOL isClosed;
TerminateThread(workerThreadHolderPtr->mHworkerThread, 0);

/*if (RtlFreeUserThreadStack != NULL)
RtlFreeUserThreadStack(GetCurrentProcess(), workerThreadHolderPtr->mHworkerThread);*/

isClosed = CloseHandle(workerThreadHolderPtr->mHworkerThread);

workerThreadHolderPtr->mIsWorkerStarted = 0;

workerThreadHolderPtr->mHworkerThread =
CreateThread(
NULL,
STK_SIZE,
WorkerThreadFun,
(PVOID)workerThreadHolderPtr,
STACK_SIZE_PARAM_IS_A_RESERVATION,
NULL);
}
}

workerThreadHolderPtr->mGuardThreadState = GRD_READY;

WakeAllConditionVariable(&workerThreadHolderPtr->mThreadReadyCond);
}

return 0;
}

void Start(WorkerThreadHolder *workerThreadHolderPtr)
{
workerThreadHolderPtr->mGuardThreadState = GRD_IDLE;

workerThreadHolderPtr->mIsWorkerStarted = 0;

InitializeConditionVariable(&workerThreadHolderPtr->mThreadReadyCond);
InitializeConditionVariable(&workerThreadHolderPtr->mStartTaskCond);
InitializeConditionVariable(&workerThreadHolderPtr->mTaskFinishedCond);
InitializeCriticalSection(&workerThreadHolderPtr->mLock);

workerThreadHolderPtr->mHworkerThread =
CreateThread(
NULL,
STK_SIZE,
WorkerThreadFun,
(LPVOID)workerThreadHolderPtr,
STACK_SIZE_PARAM_IS_A_RESERVATION,
NULL);

workerThreadHolderPtr->mHworkerGroupThread =
CreateThread(
NULL,
0,
WorkerGuardThreadFun,
(LPVOID)workerThreadHolderPtr,
0,
NULL);
}

void ExecuteTask(WorkerThreadHolder *workerThreadHolderPtr)
{
assert(workerThreadHolderPtr->mHworkerThread != NULL);
assert(workerThreadHolderPtr->mHworkerGroupThread != NULL);

EnterCriticalSection(&workerThreadHolderPtr->mLock);

for (;;)
{
if (workerThreadHolderPtr->mGuardThreadState == GRD_READY /* && workerThreadHolderPtr->mIsWorkerStarted != 0 */)
break;

SleepConditionVariableCS(
&workerThreadHolderPtr->mThreadReadyCond,
&workerThreadHolderPtr->mLock,
INFINITE);
}

/* just poll */
for (;;)
{
if (workerThreadHolderPtr->mIsWorkerStarted != 0)
break;
}

workerThreadHolderPtr->mGuardThreadState = GRD_TASKSTARTING;

WakeAllConditionVariable(&workerThreadHolderPtr->mStartTaskCond);

LeaveCriticalSection(&workerThreadHolderPtr->mLock);
}

/*----------------------------------------------------------------------------*/

int main(int argc, char *argv[])
{
int i;
WorkerThreadHolder workerThreadHolder;

/*
HMODULE NTLibrary = GetModuleHandleW(L"ntdll.dll");
RtlFreeUserThreadStack = (PRtlFreeUserThreadStack)GetProcAddress(NTLibrary, "RtlFreeUserThreadStack");
*/

Start(&workerThreadHolder);

for(i = 0;; ++i)
{
ExecuteTask(&workerThreadHolder);
printf("%d Execution started...\n", i);
/*fflush(stdout);*/
}

return 0;
}

使用 Visual Studio 2015 测试,vc 命令行:/GS-/analyze-/W3/Zc:wchar_t/ZI/Gm/Od/Fd"Debug\vc140.pdb"/Zc:inline/fp:precise/D "WIN32"/D "_D​​EBUG"/D "_CONSOLE"/D "_UNICODE"/D "UNICODE"/errorReport:prompt/WX-/Zc:forScope/Gd/Oy/MDd/Fa"Debug\"/nologo/Fo"Debug\"/Fp"Debug\ConsoleApplication1.pch"

链接器:/OUT:"C:\Users\cherney\documents\visual studio 2015\Projects\ConsoleApplication1\Debug\ConsoleApplication1.exe"/MANIFEST/NXCOMPAT/PDB:"C:\Users\cherney\documents\visual studio 2015\Projects\ConsoleApplication1\Debug\ConsoleApplication1.pdb"/DYNAMICBASE "kernel32.lib""user32.lib""gdi32.lib""winspool.lib""comdlg32.lib""advapi32.lib""shell32.lib""ole32.lib""oleaut32.lib""uuid.lib""odbc32.lib""odbccp32.lib"/DEBUG/MACHINE:X86/INCREMENTAL/PGD:"C:\Users\cherney\documents\visual studio 2015\Projects\ConsoleApplication1\Debug\ConsoleApplication1.pgd"/SUBSYSTEM:CONSOLE/MANIFESTUAC:"level='asInvoker' uiAccess='false'"/ManifestFile:"Debug\ConsoleApplication1.exe.intermediate.manifest"/ERRORREPORT:PROMPT/NOLOGO/TLBID:1

最佳答案

“TerminateThread”是“危险的”,实际上可能不会发生某些取消分配(参见 https://learn.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-terminatethread )。最好重新设计代码以在不使用“TerminateThread”的情况下干净地退出线程。

关于c++ - TerminateThread() with CloseHandle() on thread which uses only stack plain variables (without alloc) 泄漏内存?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54821048/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com