Compartilhar via


Evitar contenção de heap

Os gerenciadores de cadeia de caracteres padrão fornecidos por MFC e ATL são wrappers simples sobre um heap global. Esse heap global é totalmente thread-safe, o que significa que vários threads podem alocar e liberar memória dele simultaneamente sem corromper o heap. Para ajudar a fornecer acesso thread-safe, o heap precisa serializar o acesso a si mesmo. Isso geralmente é feito com uma seção crítica ou mecanismo de bloqueio semelhante. Sempre que dois threads tentam acessar o heap simultaneamente, um thread é bloqueado até que a solicitação do outro thread seja concluída. Para muitos aplicativos, essa situação raramente ocorre e o impacto no desempenho do mecanismo de bloqueio do heap é insignificante. No entanto, para aplicativos que acessam frequentemente o heap de vários threads de contenção para o bloqueio do heap pode fazer com que o aplicativo seja executado mais lento do que se ele fosse de thread único (mesmo em computadores com várias CPUs).

Aplicativos que usam CStringT são especialmente suscetíveis à contenção de heap porque as operações em objetos CStringT frequentemente exigem realocação do buffer de cadeia de caracteres.

Uma maneira de aliviar a contenção de heap entre threads é fazer com que cada thread aloque cadeias de caracteres de um heap local de thread privado. Desde que as cadeias de caracteres alocadas com o alocador de um thread específico sejam usadas somente nesse thread, o alocador não precisa ser thread-safe.

Exemplo

O exemplo a seguir ilustra um procedimento de thread que aloca seu próprio heap privado não thread-safe a ser usado para cadeias de caracteres nesse thread:

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);
}

Comentários

Vários threads podem estar em execução usando esse mesmo procedimento de thread, mas como cada thread tem seu próprio heap, não há contenção entre threads. Além disso, o fato de que cada heap não é thread-safe dá um aumento mensurável no desempenho, mesmo que apenas uma cópia do thread esteja em execução. Isso é o resultado do heap não usar operações interligadas caras para proteger contra acesso simultâneo.

Para um procedimento de thread mais complexo, pode ser conveniente armazenar um ponteiro para o gerenciador de cadeias de caracteres do thread em um slot do TLS (armazenamento local de thread). Isso permite que outras funções chamadas pelo procedimento de thread acessem o gerenciador de cadeias de caracteres do thread.

Confira também

Gerenciamento de memória com CStringT