Pregunta

I era la depuración de una aplicación multi-roscado y pareció que la estructura interna de CRITICAL_SECTION. He encontrado LockSemaphore miembro de datos de CRITICAL_SECTION interesante.

Parece que Critcal Section es un evento de restablecimiento automático (no un semáforo como su nombre indica) y el sistema operativo crea este evento en silencio cuando por primera vez un hilo espera en Critical Section que está bloqueado por algún otro hilo.

Ahora, me pregunto es siempre más rápido sección crítica? Evento es un objeto de núcleo y cada objeto sección crítica se asocia con objeto de evento <=> entonces cómo puede ser más rápido en comparación con otros objetos del núcleo como objeto mutex? Además, ¿qué objeto de evento interno en realidad afecta al rendimiento de la sección crítica?

Aquí está la estructura de la <=>:

struct RTL_CRITICAL_SECTION
{
    PRTL_CRITICAL_SECTION_DEBUG DebugInfo;
    LONG LockCount;
    LONG RecursionCount;
    HANDLE OwningThread;
    HANDLE LockSemaphore;
    ULONG_PTR SpinCount;
};
¿Fue útil?

Solución

Cuando se dice que una sección crítica es "rápida", que significan "que es barato de adquirir uno cuando no está bloqueado por otro hilo".

[Tenga en cuenta que si es que ya está bloqueado por otro hilo, entonces no importa tanto lo rápido que es.]

La razón por la que es tan rápido es porque, antes de entrar en el núcleo, que utiliza el equivalente de InterlockedIncrement en uno de los LONG campo (tal vez en el campo de la LockCount) y si tiene éxito entonces se considera adquirió la cerradura sin haber pasado en el kernel.

El API se <=> Creo implementado en modo de usuario como un "LOCK INC" código de operación ... en otras palabras, se puede adquirir una sección crítica sin oposición sin hacer ninguna transición anillo en el kernel en absoluto.

Otros consejos

En el trabajo de rendimiento, algunas cosas que entran en la categoría "siempre" :) Si implementa algo por sí mismo que es similar a una sección crítica OS utilizando otras primitivas entonces las probabilidades son que será más lento en la mayoría de los casos.

La mejor manera de responder a su pregunta es con medidas de rendimiento. Cómo utilizar objetos realizan es muy depende del escenario. Por ejemplo, las secciones críticas son en general considerados 'rápido' si la contención es baja. También se consideran rápidamente si el tiempo de bloqueo es menor que el tiempo de cuenta giro.

Lo más importante es determinar si la contención en una sección crítica es la primera orden factor limitante en su aplicación. Si no, entonces sólo tiene que utilizar una sección crítica normaly y trabajar en sus aplicaciones principal cuello de botella (o cuello).

Si el rendimiento de la sección crítica es crítica, entonces se puede considerar lo siguiente.

  1. set cuidadosamente el recuento de bloqueos de giro para sus secciones críticas 'calientes'. Si el rendimiento es de suma importancia, entonces el trabajo aquí vale la pena. Recuerde, mientras que el bloqueo de bucle hace evitar el modo de usuario al kernel de transición, que consume tiempo de CPU a un ritmo frenético - mientras gira, nada más puede utilizar ese tiempo de CPU. Si un bloqueo se mantiene durante el tiempo suficiente, entonces el hilo hilado bloqueará real, liberando esa CPU para otras tareas.
  2. Si usted tiene un patrón de lectura / escritura a continuación, considere el uso de la Delgado lector / escritor (SRW) bloquea . La desventaja aquí es que sólo están disponibles en Vista y Windows Server 2008 y los productos más nuevos.
  3. Usted puede ser capaz de utilizar variables de condición con su sección crítica para minimizar la votación y la contención, despertando las discusiones sólo cuando sea necesario. Una vez más, estos son compatibles con Vista y Windows Server 2008 y los productos más nuevos.
  4. Considere el uso de enclavamiento Listas enlazadas sencillas ( SLIST) - estos son eficientes y 'lock libre'. Incluso mejor, que son compatibles con XP y Windows Server 2003 y los productos más nuevos.
  5. Examine su código -. Usted puede ser capaz de romper una cerradura 'caliente' por refactorización algo de código y el uso de una operación con enclavamiento, o SLIST para la sincronización y comunicación

En resumen - escenarios de ajuste que tienen la contención de bloqueo puede ser difícil (pero interesante!) Trabajo. Centrarse en medir el rendimiento de las aplicaciones y comprensión donde sus caminos son calientes. Las herramientas Xperf en la Kit de herramientas de rendimiento de Windows es tu amigo :) Acabamos de lanzar la versión 4.5 de Microsoft Windows SDK para Windows 7 y .NET Framework 3.5 SP1 ( ISO es aquí , instalador web aquí ). Puede encontrar el foro para las herramientas Xperf aquí . V4.5 es totalmente compatible con Win7, Vista, Windows Server 2008 -. Todas las versiones

CriticalSections es más rápido, pero InterlockedIncrement / InterlockedDecrement es más. Vea este ejemplo de implementación uso LightweightLock copia completa .

Los CriticalSections harán girar un corto tiempo (algunos ms) y mantener el control de si el bloqueo está libre. Después de la escisión contar 'tiempo de espera', que será luego caer de nuevo al evento núcleo. Así, en el caso de que el titular de la cerradura se sale rápidamente, que nunca tenga que hacer la transición caro al núcleo código.

EDIT: fuimos y encontramos algunos comentarios en mi código: al parecer, el Gestor Montón MS utiliza una cuenta de giro de 4000 (incrementos enteros, no ms)

Esta es una forma de verlo:

Si no hay contención, entonces el bloqueo de bucle es muy rápido en comparación con ir al modo kernel para un objeto mutex.

Cuando hay contención, una Sección Crítica es ligeramente más caro que utilizar un mutex directamente (debido al trabajo extra para detectar el estado spinlock).

Por lo tanto, se reduce a una media ponderada, donde las ponderaciones dependen de las características específicas de su patrón de llamadas. Dicho esto, si tiene poca contención, a continuación, una Sección Crítica es gran victoria. Si, por el contrario, tiene siempre un montón de contención, entonces sería el pago de una muy pequeña penalización sobre el uso directo de un objeto mutex. Pero en ese caso, lo que se obtiene por el cambio a un objeto mutex es pequeño, por lo que probablemente sería mejor tratar de reducir la contención.

sección crítica es más rápido que el mutex por qué, porque la sección crítica no es un objeto de núcleo. Esto es parte de la memoria global del proceso actual. Mutex realidad reside en el núcleo y creación de objetos mutext requiere un interruptor kernel pero en el caso de la sección crítica no. A pesar de que la sección crítica es rápido, habrá un interruptor del núcleo durante el uso de la sección crítica cuando las discusiones van a esperar estado. Esto se debe a la programación de subprocesos que ocurre en el lado del núcleo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top