Articulo de referencia

Sección crítica

En la programación concurrente , los accesos concurrentes a recursos compartidos pueden provocar un comportamiento inesperado o erróneo. Por lo tanto, las partes del programa do...

En la programación concurrente , los accesos concurrentes a recursos compartidos pueden provocar un comportamiento inesperado o erróneo. Por lo tanto, las partes del programa donde se accede al recurso compartido deben protegerse de forma que se evite el acceso concurrente. Una forma de hacerlo es mediante una sección crítica o región crítica . A esta sección protegida no puede acceder más de un proceso o hilo a la vez; los demás se suspenden hasta que el primero abandona la sección crítica. Normalmente, la sección crítica accede a un recurso compartido, como una estructura de datos , un dispositivo periférico o una conexión de red, que no funcionaría correctamente en el contexto de múltiples accesos concurrentes. [ 1 ]

Necesidad de secciones críticas

Diferentes códigos o procesos pueden constar de la misma variable u otros recursos que deben leerse o escribirse, pero cuyos resultados dependen del orden en que se realizan las acciones. Por ejemplo, si el proceso A debe leer una variable x  , y el proceso  B debe escribir en la variable x al mismo tiempo, el proceso  A podría obtener el valor antiguo o el nuevo de x .

Diagrama de flujo que muestra la necesidad de una sección crítica

Proceso A:

// Proceso A . . b = x + 5 ; // la instrucción se ejecuta en el tiempo = Tx .

Proceso B:

// Proceso B . . x = 3 + z ; // la instrucción se ejecuta en el tiempo = Tx .

En los casos en que no se requiere un mecanismo de bloqueo con granularidad fina, una sección crítica es importante. En el ejemplo anterior, si A necesita leer el valor actualizado de x , ejecutar los procesos  A y  B simultáneamente podría no dar los resultados deseados. Para evitar esto, la variable x está protegida por una sección crítica. Primero, B obtiene acceso a la sección. Una vez que B termina de escribir el valor, A obtiene acceso a la sección crítica y se puede leer la variable x .

Al controlar cuidadosamente qué variables se modifican dentro y fuera de la sección crítica, se evita el acceso concurrente a la variable compartida. Una sección crítica se utiliza normalmente cuando un programa multihilo debe actualizar varias variables relacionadas sin que otro hilo realice cambios conflictivos en esos datos. En una situación similar, una sección crítica puede utilizarse para garantizar que un recurso compartido, como una impresora, solo sea accesible por un proceso a la vez.

Implementación de secciones críticas

La implementación de las secciones críticas varía entre los diferentes sistemas operativos.

Una sección crítica generalmente termina en un tiempo finito, [ 2 ] y un hilo, tarea o proceso debe esperar un tiempo fijo para entrar en ella ( espera limitada ). Para garantizar el uso exclusivo de las secciones críticas, se requiere algún mecanismo de sincronización al inicio y al final del programa.

Una sección crítica es una parte de un programa que requiere la exclusión mutua del acceso.

Bloqueos y secciones críticas en múltiples hilos

Como se muestra en la figura, [ 3 ] en el caso de exclusión mutua ( mutex ), un hilo bloquea una sección crítica mediante técnicas de bloqueo cuando necesita acceder al recurso compartido, y otros hilos deben esperar su turno para entrar en la sección. Esto evita conflictos cuando dos o más hilos comparten el mismo espacio de memoria y quieren acceder a un recurso común. [ 2 ]

Pseudocódigo para implementar la sección crítica

El método más sencillo para evitar cualquier cambio en el control del procesador dentro de la sección crítica es implementar un semáforo. En sistemas monoprocesador, esto se puede lograr deshabilitando las interrupciones al entrar en la sección crítica, evitando las llamadas al sistema que puedan provocar un cambio de contexto dentro de la sección y restaurando las interrupciones a su estado anterior al salir. Con esta implementación, cualquier hilo de ejecución que entre en una sección crítica del sistema impedirá que cualquier otro hilo, incluyendo una interrupción, reciba tiempo de procesamiento en la CPU hasta que el hilo original abandone su sección crítica.

Este método de fuerza bruta puede mejorarse mediante el uso de semáforos . Para acceder a una sección crítica, un hilo debe obtener un semáforo, que libera al salir de dicha sección. Otros hilos no pueden acceder a la sección crítica simultáneamente con el hilo original, pero pueden tomar el control de la CPU y ejecutar otro código, incluidas otras secciones críticas protegidas por diferentes semáforos. El bloqueo por semáforo también tiene un límite de tiempo para evitar un interbloqueo, en el que un solo proceso adquiere un bloqueo indefinidamente, bloqueando a los demás procesos que necesitan utilizar el recurso compartido protegido por la sección crítica.

Usos de las secciones críticas

Secciones críticas a nivel de núcleo

Por lo general, las secciones críticas impiden la migración de hilos y procesos entre procesadores, así como la interrupción de procesos e hilos por parte de otros procesos e hilos.

Las secciones críticas suelen permitir el anidamiento. El anidamiento permite acceder a múltiples secciones críticas y salir de ellas con poco coste.

Si el planificador interrumpe el proceso o hilo actual en una sección crítica, permitirá que el proceso o hilo en ejecución complete dicha sección o lo programará para otro cuanto completo. El planificador no migrará el proceso o hilo a otro procesador ni programará la ejecución de otro proceso o hilo mientras el actual se encuentre en una sección crítica.

De forma similar, si se produce una interrupción en una sección crítica, la información de la interrupción se registra para su posterior procesamiento y la ejecución se devuelve al proceso o hilo en dicha sección. Una vez que se sale de la sección crítica, y en algunos casos se completa el cuanto programado, se ejecutará la interrupción pendiente. El concepto de cuanto de programación se aplica a las políticas de programación " round-robin " y similares .

Dado que las secciones críticas solo pueden ejecutarse en el procesador en el que se ingresan, la sincronización solo es necesaria dentro del procesador en ejecución. Esto permite que las secciones críticas se ingresen y salgan prácticamente sin costo. No se requiere sincronización entre procesadores. Solo se necesita la sincronización del flujo de instrucciones. [ 4 ] La mayoría de los procesadores proporcionan la cantidad necesaria de sincronización interrumpiendo el estado de ejecución actual. Esto permite que, en la mayoría de los casos, las secciones críticas no sean más que un recuento por procesador de las secciones críticas ingresadas.

Las mejoras de rendimiento incluyen la ejecución de las interrupciones pendientes al finalizar todas las secciones críticas y la activación del planificador al finalizar dichas secciones. Además, las interrupciones pendientes pueden transferirse a otros procesadores para su ejecución.

Las secciones críticas no deben utilizarse como un mecanismo de bloqueo prolongado. Deben ser lo suficientemente cortas como para que se pueda acceder a ellas, ejecutarlas y salir de ellas sin que se produzcan interrupciones por parte del hardware ni del planificador.

Las secciones críticas a nivel del núcleo son la base del problema del bloqueo del software .

Secciones críticas en las estructuras de datos

En la programación paralela, el código se divide en hilos. Las variables con conflictos de lectura y escritura se dividen entre los hilos y cada hilo tiene una copia de ellas. Las estructuras de datos como las listas enlazadas , los árboles y las tablas hash tienen variables de datos que están enlazadas y no se pueden dividir entre hilos; por lo tanto, implementar el paralelismo es muy difícil. [ 5 ] Para mejorar la eficiencia de la implementación de estructuras de datos, se pueden ejecutar en paralelo múltiples operaciones como inserción, eliminación y búsqueda. Al realizar estas operaciones, pueden darse escenarios en los que un hilo esté buscando el mismo elemento y otro lo esté eliminando. En tales casos, el resultado puede ser erróneo . El hilo que busca el elemento puede tener una coincidencia, mientras que el otro hilo puede eliminarlo posteriormente. Estos escenarios causarán problemas en la ejecución del programa al proporcionar datos falsos. Para evitar esto, un método es mantener toda la estructura de datos en una sección crítica para que solo se maneje una operación a la vez. Otro método es bloquear el nodo en uso en la sección crítica, para que otras operaciones no utilicen el mismo nodo. El uso de secciones críticas, por lo tanto, garantiza que el código proporcione los resultados esperados. [ 5 ]

Secciones críticas en relación con los periféricos

También existen secciones críticas en el código que manipula periféricos externos, como dispositivos de entrada/salida. Los registros de un periférico deben programarse con ciertos valores en una secuencia específica. Si dos o más procesos controlan un dispositivo simultáneamente, ninguno de ellos lo tendrá en el estado requerido, lo que provocará un comportamiento incorrecto.

Cuando se debe generar una unidad de información compleja en un dispositivo de salida mediante la emisión de múltiples operaciones de salida, se requiere acceso exclusivo para que otro proceso no corrompa los datos intercalando sus propios bits de salida.

En la dirección de entrada, se requiere acceso exclusivo al leer un dato complejo mediante múltiples operaciones de entrada independientes. Esto evita que otro proceso consuma parte de los datos, lo que podría provocar corrupción.

Los dispositivos de almacenamiento proporcionan una forma de memoria. El concepto de secciones críticas es igualmente relevante para los dispositivos de almacenamiento que para las estructuras de datos compartidas en la memoria principal. Un proceso que realiza múltiples operaciones de acceso o actualización en un archivo está ejecutando una sección crítica que debe protegerse con un mecanismo de bloqueo de archivos adecuado .

Véase también

Referencias

  1. Raynal, Michel (2012). Programación concurrente: algoritmos, principios y fundamentos . Springer Science & Business Media. pág.  9. ISBN 978-3642320279.
  2. 1 2 Jones, M. Tim (2008). Programación de aplicaciones GNU/Linux (2.ª ed.). [Hingham, Mass.] Charles River Media. pág. 264. ISBN  978-1-58450-568-6.
  3. Chen, Stenstrom, Guancheng, Per (10-16 de noviembre de 2012). «Análisis de bloqueos críticos: Diagnóstico de cuellos de botella en secciones críticas en aplicaciones multihilo». Conferencia Internacional de 2012 sobre Computación de Alto Rendimiento, Redes, Almacenamiento y Análisis . págs. 1-11 . doi : 10.1109/sc.2012.40 . ISBN  978-1-4673-0805-2. S2CID 12519578 . {{cite book}}: CS1 maint: varios nombres: lista de autores ( enlace )
  4. Dubois, Scheurich, Michel, Christoph (1988). "Sincronización, coherencia y ordenación de eventos en multiprocesadores". Computer . 21 (2): 9– 21. doi : 10.1109/2.15 . S2CID 1749330 . {{cite journal}}: CS1 maint: varios nombres: lista de autores ( enlace )
  5. 1 2 Solihin, Yan (17 de noviembre de 2015). Fundamentos de la arquitectura multinúcleo paralela . Taylor & Francis. ISBN 9781482211184.
  • Documentación de la sección crítica en la página web de Microsoft Docs.
  • Tutorial sobre secciones críticas
  • Ejemplos de código para Mutex
  • Tutorial sobre semáforos
  • Contención de bloqueos en secciones críticas
Obtenido de " https://en.wikipedia.org/w/index.php?title=Critical_section&oldid=1326089050 "