Compartir a través de


Prevención de la contención del montón

Los administradores de cadenas predeterminados proporcionados por MFC y ATL son contenedores simples sobre un montón global. Este montón global es totalmente seguro para subprocesos, lo que significa que varios subprocesos pueden asignar y liberar memoria de él de forma simultánea sin dañar el montón. Para ayudar a proporcionar seguridad para subprocesos, el montón tiene que serializar el acceso a sí mismo. Esto suele realizarse con una sección crítica o un mecanismo de bloqueo similar. Cada vez que dos subprocesos intentan acceder al montón de forma simultánea, se bloquea un subproceso hasta que finaliza la solicitud del otro. En muchas aplicaciones, esta situación no se suele dar y el impacto en el rendimiento del mecanismo de bloqueo del montón es insignificante. Pero para las aplicaciones que acceden con frecuencia al montón desde la contención de varios subprocesos para el bloqueo del montón, la aplicación puede hacer que la aplicación se ejecute con más lentitud que si fuera de un solo subproceso (incluso en máquinas con varias CPU).

Las aplicaciones que usan CStringT son especialmente susceptibles a la contención del montón porque las operaciones en objetos CStringT suelen requerir reasignación del búfer de cadenas.

Una manera de aliviar la contención del montón entre subprocesos es hacer que cada subproceso asigne cadenas desde un montón local de subprocesos privado. Siempre que las cadenas asignadas con el asignador de un subproceso determinado solo se usen en ese subproceso, el asignador no tiene que ser seguro para subprocesos.

Ejemplo

En el ejemplo siguiente se muestra un procedimiento de subproceso que asigna su propio montón privado no seguro para subprocesos que se usará para las cadenas de ese subproceso:

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

Comentarios

Se podrían ejecutar varios subprocesos con este mismo procedimiento de subproceso, pero dado que cada subproceso tiene su propio montón, no hay contención entre subprocesos. Además, el hecho de que cada montón no sea seguro para subprocesos proporciona un aumento medible en el rendimiento incluso si solo se está ejecutando una copia del subproceso. Este es el resultado del montón que no usa operaciones de interbloqueo costosas para protegerse contra el acceso simultáneo.

Para un procedimiento de subproceso más complicado, puede ser conveniente almacenar un puntero al administrador de cadenas del subproceso en una ranura de almacenamiento local para el subprocesos (TLS). Esto permite que otras funciones a las que ha llamado el procedimiento de subproceso accedan al administrador de cadenas del subproceso.

Consulte también

Administración de memoria con CStringT