Share via


힙 경합 방지

MFC 및 ATL에서 제공하는 기본 문자열 관리자는 전역 힙 위에 있는 간단한 래퍼입니다. 이 전역 힙은 완전히 스레드로부터 안전하므로 여러 스레드가 힙을 손상시키지 않고 동시에 메모리를 할당하고 해제할 수 있습니다. 스레드 보안을 제공하기 위해 힙은 자체에 대한 액세스를 직렬화해야 합니다. 이 작업은 일반적으로 중요한 섹션 또는 유사한 잠금 메커니즘을 사용하여 수행됩니다. 두 스레드가 동시에 힙에 액세스하려고 할 때마다 다른 스레드의 요청이 완료될 때까지 한 스레드가 차단됩니다. 많은 애플리케이션에서 이 상황은 거의 발생하지 않으며 힙 잠금 메커니즘의 성능 영향은 무시할 수 있습니다. 그러나 힙 잠금에 대한 여러 스레드 경합에서 힙에 자주 액세스하는 애플리케이션의 경우 애플리케이션이 단일 스레드(여러 CPU가 있는 컴퓨터에서도)보다 느리게 실행될 수 있습니다.

CStringT를 사용하는 애플리케이션은 개체에 대한 작업에 문자열 버퍼를 다시 할당해야 하는 경우가 많기 때문에 힙 경합에 CStringT 특히 취약합니다.

스레드 간의 힙 경합을 완화하는 한 가지 방법은 각 스레드가 프라이빗 스레드 로컬 힙에서 문자열을 할당하도록 하는 것입니다. 특정 스레드의 할당자로 할당된 문자열이 해당 스레드에서만 사용되는 한 할당자는 스레드로부터 안전할 필요가 없습니다.

예시

아래 예제에서는 해당 스레드의 문자열에 사용할 자체 프라이빗 비 스레드로부터 안전한 힙을 할당하는 스레드 프로시저를 보여 줍니다.

DWORD WINAPI WorkerThreadProc(void* pBase)
{
   // Declare a non-thread-safe heap just for this thread:
   CWin32Heap stringHeap(HEAP_NO_SERIALIZE, 0, 0);

   // Declare a string manager that uses the thread's heap:
   CAtlStringMgr stringMgr(&stringHeap);

   int nBase = *((int*)pBase);
   int n = 1;
   for(int nPower = 0; nPower < 10; nPower++)
   {
      // Use the thread's string manager, instead of the default:
      CString strPower(&stringMgr);

      strPower.Format(_T("%d"), n);
      _tprintf_s(_T("%s\n"), strPower);
      n *= nBase;
   }

   return(0);
}

설명

동일한 스레드 프로시저를 사용하여 여러 스레드를 실행할 수 있지만 각 스레드에는 자체 힙이 있으므로 스레드 간에 경합이 없습니다. 또한 각 힙이 스레드로부터 안전하지 않다는 사실은 스레드의 복사본 하나만 실행 중이더라도 성능이 측정 가능한 향상을 제공합니다. 이는 동시 액세스로부터 보호하기 위해 비용이 많이 드는 연동 작업을 사용하지 않는 힙의 결과입니다.

더 복잡한 스레드 프로시저의 경우 스레드의 문자열 관리자에 대한 포인터를 스레드 TLS(로컬 스토리지) 슬롯에 저장하는 것이 편리할 수 있습니다. 이렇게 하면 스레드 프로시저에서 호출하는 다른 함수가 스레드의 문자열 관리자에 액세스할 수 있습니다.

참고 항목

CStringT를 사용한 메모리 관리