¿Qué tres tipos de semáforos se pueden usar para implementar una solución al problema de la sección crítica sin riesgo de inanición?

Ok, tratemos de abordar esta pregunta paso a paso. Primero, definamos la inanición, luego observemos diferentes semáforos y las propiedades que tienen, y finalmente intentemos evaluar el riesgo de inanición con diferentes semáforos.

TL; DR La cola de bloqueo es menos susceptible, seguida por el conjunto de bloqueo y luego ocupado esperar semáforo.

La inanición es una situación en la que un proceso no puede tener acceso constante a un recurso compartido, lo que dificulta su ejecución. Este estado es diferente tanto del punto muerto como del bloqueo en vivo, ya que aquí todos los procesos en este estado están progresando hacia sus objetivos establecidos, pero este progreso es extremadamente lento, porque no poseen la propiedad exclusiva de un recurso compartido durante una cantidad suficientemente larga de tiempo.

La inanición puede ser causada por un error en el algoritmo de programación, que no asigna recursos equitativamente a todos los procesos. Un ejemplo de un algoritmo de programación que evita este problema es una cola prioritaria con la técnica de envejecimiento. A cada proceso se le asigna una prioridad. El proceso con mayor prioridad gana la propiedad del recurso compartido y su prioridad disminuye. La prioridad de todos los procesos de espera aumenta gradualmente, lo que lleva a la eventual concesión de la propiedad a ellos.

Otra posible causa de este estado es una fuga de recursos, que conduce a un recurso típicamente abundante que muchos procesos requieren para convertirse en uno deficitario, lo que lleva a una competencia por el mismo y al hambre. Esta situación puede ser causada intencionalmente por ataques de denegación de servicio en un sistema. [1]

Ahora, examinemos los diferentes tipos de semáforos:

  • El semáforo de espera ocupada es el semáforo más simple, donde los procesos bloqueados verifican repetidamente si la condición del semáforo les permite agarrar el bloqueo.

int i = 0;

nulo m1 () {
/ * espera el bloqueo * /
mientras que (i! = 0) {}
i = 1;
/ * ejecutar lógica m1 * /
i = 0;
}

nulo m2 () {
/ * espera el bloqueo * /
mientras que (i! = 0) {}
i = 2;
/ * ejecuta la lógica m2 * /
i = 0;
}

Sin embargo, se considera una mala elección de diseño, ya que no puede predecir cuánto tiempo se ejecutará el ciclo “no hacer nada”, antes de verificar nuevamente la condición. En el código anterior, no se sabe cuántas veces se ejecuta el ciclo (i! = 0), y eso puede consumir mucho tiempo de CPU, lo que lleva a la quema de ciclos innecesarios de CPU. Debe considerarse si y solo si las cerraduras se toman por un corto período de tiempo.

  • El bloque de semáforo de cola es una versión más avanzada del concepto de semáforo, donde los recursos disponibles se almacenan en una cola. Cuando un proceso quiere adquirir un bloqueo, toma un recurso de la cola. Cuando un proceso devuelve el bloqueo, la cola recupera el mismo recurso o lo recicla si tiene que volver a un estado en blanco. Si la cola no tiene un recurso, el proceso se suspende, hasta que un recurso esté disponible, en lugar de grabar ciclos de CPU. Es importante tener en cuenta que la cola despierta los procesos en el orden FIFO de su suspensión. Un ejemplo de implementación de bloqueo de cola en Java.
  • El conjunto de semáforos de bloqueo funciona de manera similar a la cola de bloqueo, pero una diferencia importante es que activa un proceso aleatorio, cuando un recurso está disponible, sin preservar el orden de las solicitudes del recurso.

Ahora, tratemos de ver algunos escenarios posibles que pueden ocurrir con diferentes semáforos que pueden conducir al hambre:

  • Ocupado esperar semáforo: un proceso entra en la sección crítica, mientras que el otro comprueba constantemente si el bloqueo está libre. Debido a alguna peculiaridad en la programación, el segundo proceso quema constantemente los ciclos de la CPU, mientras que el primero espera su turno para usar la CPU durante largos períodos de tiempo, ya que sus operaciones son más lentas que el ciclo de no hacer nada. Ahora, el sistema está en estado de hambre;
  • Bloqueo del semáforo establecido : un gran número de procesos ha colocado solicitudes en el mismo recurso. Para empeorar las cosas, las nuevas solicitudes llegan a la misma velocidad a medida que los recursos están disponibles. Debido a alguna peculiaridad de la selección aleatoria, un subconjunto de estos procesos no recibe recursos durante mucho tiempo, a pesar de que estuvieron allí primero. Ahora, este subconjunto está en hambre;
  • Bloqueo del semáforo de la cola : ambos casos descritos anteriormente se manejan con gracia, ya que en el primer caso no se realiza la grabación del ciclo de la CPU, y en el segundo caso los procesos se sirven en orden FIFO. Sin embargo, la inanición también puede ocurrir debido a la falta general de recursos en el sistema, y ​​en tales casos es inevitable, incluso en un escenario relativamente justo de la cola de bloqueo, muchos procesos pueden tener que esperar largos períodos de tiempo para obtener el recurso, causando hambre.

Para concluir, el bloqueo del semáforo de la cola es menos susceptible a la inanición, ya que no solo evita el uso sin sentido de los ciclos de la CPU, sino que también atiende las solicitudes en el orden FIFO. Luego viene el conjunto de bloqueo, ya que no quema el tiempo de CPU, sino que sirve los procesos en orden aleatorio, lo que lo hace más propenso a la inanición. Finalmente, los semáforos de espera ocupados no deben usarse, ya que no solo no pueden garantizar el orden de las solicitudes, sino que también queman los ciclos de la CPU, ya que todos los solicitantes verifican si el recurso está disponible.

Enlaces:

  • Espera ocupada – Wikipedia
  • Spinlock – Wikipedia – lo mismo que ocupado esperando
  • Bloqueo de colas
  • Conferencia sobre concurrencia
  • La respuesta de Nikita Gureev a ¿Qué estados de error además de “Deadlock” o “Livelock” son posibles en la programación concurrente? – parte de inutilización reutilizada, también entra en detalles sobre otro estado de error en la programación concurrente

Notas al pie

[1] La respuesta de Nikita Gureev a ¿Qué estados de error además de “Deadlock” o “Livelock” son posibles en la programación concurrente?