Windows在线程关闭时创建事件

时间:2014-07-07 04:26:19

标签: c++ windows multithreading unit-testing window-handles

我正在尝试将句柄泄漏检测添加到我的代码上的单元测试框架中。 (Windows 7,x64 VS2010)

我基本上在每次单元测试之前和之后调用GetProcessHandleCount()。 这种方法很好,除非在测试过程中创建/销毁线程。

似乎windows偶尔会在线程关闭时创建1-3个事件。在循环中运行相同的测试不会增加事件创建计数。 (例如,在循环中运行测试5000次只会导致创建1-3个额外事件)

我不会在自己的代码中手动创建事件。

这似乎与此问题相似: boost::thread causing small event handle leak? 但我正在手动创建/关闭线程。

我遵循了这段代码: http://blogs.technet.com/b/yongrhee/archive/2011/12/19/how-to-troubleshoot-a-handle-leak.aspx

从WinDbg获得了这个callstack:

Outstanding handles opened since the previous snapshot:
--------------------------------------
Handle = 0x0000000000000108 - OPEN
Thread ID = 0x00000000000030dc, Process ID = 0x0000000000000c90

0x000000007715173a: ntdll!NtCreateEvent+0x000000000000000a
0x0000000077133f26: ntdll!RtlpCreateCriticalSectionSem+0x0000000000000026
0x0000000077133ee3: ntdll!RtlpWaitOnCriticalSection+0x000000000000014e
0x000000007714e40b: ntdll!RtlEnterCriticalSection+0x00000000000000d1
0x0000000077146ad2: ntdll!LdrShutdownThread+0x0000000000000072
0x0000000077146978: ntdll!RtlExitUserThread+0x0000000000000038
0x0000000076ef59f5: kernel32!BaseThreadInitThunk+0x0000000000000015
0x000000007712c541: ntdll!RtlUserThreadStart+0x000000000000001d
--------------------------------------

如您所见,这是在线程关闭时创建的事件。

在单元测试中是否有更好的方法来执行此句柄泄漏检测?我目前唯一的选择是:

  • 忘记尝试这样做来处理泄漏检测
  • 调整一些虚拟任务以尝试创建这些虚假事件。
  • 在泄漏时允许一些小的公差值并且每次测试运行100次(因此实际泄漏将是一个很大的数量)
  • 获取不包括事件的句柄数(代码难度很大)

我也试过在VS2013中切换到使用std :: thread,但它似乎在使用时创建了很多后台线程和句柄。 (使计数差异更大)

这是一个自包含的示例,其中99%的时间(在我的计算机上)在幕后创建了一个事件。 (句柄数不同)。将启动/关闭代码置于循环中表示它不会直接泄漏,但会累积偶然的事件:

#include "stdio.h"
#include <Windows.h>
#include <process.h>

#define THREADCOUNT 3
static HANDLE s_semCommand, s_semRender;

static unsigned __stdcall ExecutiveThread(void *)
{
  WaitForSingleObject(s_semCommand, INFINITE);
  ReleaseSemaphore(s_semRender, THREADCOUNT - 1, NULL);
  return 0;
}

static unsigned __stdcall WorkerThread(void *)
{
  WaitForSingleObject(s_semRender, INFINITE);
  return 0;
}

int main(int argc, char* argv[])
{
  DWORD oldHandleCount = 0;
  GetProcessHandleCount(GetCurrentProcess(), &oldHandleCount);

  s_semCommand = CreateSemaphoreA(NULL, 0, 0xFFFF, NULL);
  s_semRender  = CreateSemaphoreA(NULL, 0, 0xFFFF, NULL);

  // Spool threads up
  HANDLE threads[THREADCOUNT];
  for (int i = 0; i < THREADCOUNT; i++)
  {
    threads[i] = (HANDLE)_beginthreadex(NULL, 4096, (i==0) ? ExecutiveThread : WorkerThread, NULL, 0, NULL);
  }

  // Signal shutdown - Wait for threads and close semaphores
  ReleaseSemaphore(s_semCommand, 1, NULL);
  for (int i = 0; i < THREADCOUNT; i++)
  {
    WaitForSingleObject(threads[i], INFINITE);
    CloseHandle(threads[i]);
  }
  CloseHandle(s_semCommand);
  CloseHandle(s_semRender);

  DWORD newHandleCount = 0;
  GetProcessHandleCount(GetCurrentProcess(), &newHandleCount);
  printf("Handle %d -> %d", oldHandleCount, newHandleCount);
    return 0;
}

0 个答案:

没有答案