Filósofo de punto muerto algoritmo de banquero problema comedor

Desde https://www.cnblogs.com/niuyourou/p/12004183.html

Sección I El problema de la comida del filósofo

Sección 2 ¿Qué es un punto muerto?

Sección 3 Definición de punto muerto

Sección 4 Condiciones para un punto muerto

Sección 5 Cómo evitar el punto muerto

    5.1 Evitación dinámica, algoritmo bancario (asignación de apalancamiento), capítulo en el contexto de la asignación de recursos

    5.2 Evitación estática, evitar el punto muerto del código de tarea

Sección 6 Tratamiento integral del punto muerto

Sección I El problema de la comida del filósofo

Supongamos que cinco filósofos se sientan alrededor de una mesa redonda y hacen una de dos cosas: comer o pensar. Cuando comen, dejan de pensar y dejan de comer cuando piensan. Hay un tazón grande de pasta en el centro de la mesa del comedor, y hay un par de palillos entre cada dos filósofos. Debido a que es difícil comer pasta con un palillo, se supone que el filósofo debe comer con dos palillos. Solo pueden usar los dos palillos a la izquierda y a la derecha. Como se muestra a continuación:

 Cada filósofo recogió dos palillos chinos a la izquierda y derecha, cinco filósofos y cinco pares de palillos chinos. Los filósofos felizmente comieron los fideos y me dieron las gracias por cierto, así que la pregunta terminó. (¿Eh? Parece mal)

El verdadero problema es este, solo hay un palillo en lugar de un par entre cada dos filósofos , el problema se muestra en la figura a continuación:

Los filósofos deben comer con dos palillos, y solo pueden usar los dos palillos a la izquierda y a la derecha.

Para el problema anterior, podemos pensar naturalmente en un algoritmo:

1. Espere a que los palillos izquierdos estén disponibles, recoja los palillos izquierdos

2. Espera a que estén disponibles los palillos correctos, recoge los palillos correctos

3. comer

4. Pon dos palillos

Obviamente, cuando el número de intentos es suficiente, hay una situación que no se puede evitar: cada filósofo ha recogido los palillos a la izquierda y está esperando los palillos a la derecha. Debido a que los palillos de la derecha están en manos del filósofo de la derecha, y el filósofo de la derecha también está esperando que el filósofo de la derecha baje los palillos, todos tienen los recursos del otro y esperan que otros lo suelten. En un estado de hambre, este es un punto muerto.

Sección 2 ¿Qué es un punto muerto?

Sabemos que la ejecución de subprocesos requiere recursos, y cada subproceso usará los recursos en un cierto orden. Si se rechaza la solicitud de recursos, el subproceso no puede continuar ejecutándose hacia abajo y esperará. Siempre hay tres pasos para que los subprocesos utilicen recursos:

1. Solicitar recursos

2. Usa los recursos

3. Libere recursos

En el sistema operativo, un subproceso debe esperar cuando no puede solicitar un recurso. Hay dos formas de esperar. Una es la espera de bloqueo; es la espera sin bloqueo, es decir, regresar inmediatamente, hacer otras cosas y luego intentar la solicitud nuevamente, o no salir para terminar el hilo.

Si el hilo espera recursos sin bloqueo, no se producirá un punto muerto. Es concebible que un filósofo solicite que fallen los palillos en la mano derecha, deje los palillos en la mano izquierda, deje de comer y siga pensando. Entonces el filósofo de la izquierda tiene dos pares de palillos. Después de comer y dejar los dos pares de palillos, los filósofos izquierdo y derecho pueden obtener dos pares de palillos. Toda la situación de asignación de recursos estará viva, y no ocurrirá ningún punto muerto.

Sin embargo, si utiliza métodos de bloqueo para esperar recursos, puede producirse un punto muerto. Cada filósofo tiene palillos y espera a que otro palillo esté disponible. Cada filósofo no dejará los palillos en su mano, por lo que todos son infinitos. Espera

Si hay n hilos T1 ~ Tn, yn recursos R1 ~ Rn. Entre ellos, Ti posee el recurso Ri, pero solicita el recurso Ri + 1, por lo que se convierte en un punto muerto. Podemos expresar esta relación de retención y espera a través de un gráfico dirigido. La línea continua indica que el recurso ya está retenido, y la línea discontinua indica que el recurso está esperando, como se muestra en la siguiente figura:

 Cada subproceso está esperando un determinado recurso, por lo que ningún subproceso puede avanzar, lo que provoca un punto muerto.

Sección 3 Definición de punto muerto

Si un grupo de subprocesos, cada subproceso está esperando un evento (el evento aquí generalmente se refiere a la liberación de recursos), y el evento de que cada subproceso espera solo puede ser emitido por otro subproceso en el grupo de subprocesos, entonces este grupo de subprocesos Se ha producido un punto muerto.

Veamos un conjunto de códigos que obviamente causan un punto muerto:

Código de copia

//线程1
new Thread(){
  @Override
   public void run(){
      synchronized(A){
            synchronized(B){
                doSomeThing....
           }
       }
   }
}

Código de copia

Código de copia

//线程2
new Thread(){
  @Override
   public void run(){
      synchronized(B){
            synchronized(A){
                doSomeThing....
           }
       }
   }
}

Código de copia

Si el subproceso 1 y el subproceso 2 se ejecutan alternativamente, 1 adquiere el bloqueo A; luego 2 se ejecuta y 2 adquiere el bloqueo B.

1 La solicitud B se rechaza porque B está en manos de 2; 2 La solicitud A se rechaza porque A está en manos de 1.

Hasta ahora, 1, 2 no se pueden ejecutar, formando el siguiente ciclo de espera:

 No estamos diciendo que el programa deba estar en punto muerto. Si el subproceso 1 adquiere dos bloqueos antes de que el subproceso 2 comience a ejecutarse, no se producirá ningún punto muerto. Pero cuando los hilos 1 y 2 se ejecutan alternativamente, la probabilidad de un punto muerto es mucho mayor que la probabilidad de que no haya punto muerto. No hablaremos de lo mucho que la probabilidad de la ocurrencia de un callejón sin salida, tenemos en cuenta el problema de la dimensión estancamiento se probable que se produzca estancamiento con el estancamiento imposible .

Por supuesto, el programa que escribimos es el mejor para evitar el punto muerto, lo que requiere que definamos claramente cuándo ocurrirá el punto muerto y evitarlo, entonces, ¿cuáles son las condiciones para el punto muerto?

Sección 4 Condiciones para un punto muerto

La aparición de un punto muerto debe cumplir cuatro condiciones:

1. Recursos limitados . Una condición muy intuitiva, como en la primera sección, si hay cinco pares de palillos en la mesa. Cada filósofo puede obtener suficientes palillos para comer al mismo tiempo, y no se producirá un punto muerto.

2. Espera . Es decir, cuando un hilo solicita un nuevo recurso, no libera el recurso adquirido. Si el filósofo solicita que los palillos de la mano derecha fallen, entonces baje los palillos de la mano izquierda, entonces el filósofo de la izquierda tendrá dos palillos.

3. No se puede evitar . Si un filósofo no solicita los palillos en la mano derecha, y luego agarra los palillos en la mano derecha, también obtendrá dos palillos.

4. Espera en un bucle . Ese es el ejemplo en la segunda sección de la imagen, me esperas y yo te espero a ti, todos esperan y mantienen una relación en un círculo cerrado.

Las cuatro condiciones anteriores son indispensables para la formación de un punto muerto. Mientras rompamos una de las condiciones, el punto muerto no ocurrirá. Entonces, ¿cómo rompemos estas condiciones para evitar un punto muerto?

Sección 5 Cómo evitar el punto muerto

Hay dos formas de evitar un punto muerto: evitación dinámica y evitación estática .

5.1 Evitación dinámica, algoritmo bancario, capítulo en el contexto de la asignación de recursos

Permítanme comenzar con un ejemplo más interesante, el apalancamiento de los bancos, veamos cómo los bancos evitan los puntos muertos.

Suplemento: Para los bancos, la liquidez son recursos (recursos informáticos o semáforos), y los prestamistas son solicitantes de recursos (hilos).

Todos sabemos que el usuario debe tener un propósito para completar el préstamo. Por simplicidad, asumimos que el propósito del usuario es usar dinero para hacer negocios, y el usuario cumple con el crédito (si tiene dinero, usted pagará).

Si el usuario puede pedir prestado hasta el valor máximo de su límite de crédito, puede cumplir con las expectativas del plan de usuario, el negocio puede hacerse y el usuario puede pagar a tiempo.

Si el usuario no obtiene el valor máximo del límite de crédito, hará que el costo del usuario sea insuficiente para completar con éxito el negocio, y no habrá suficiente dinero para pagar el préstamo, lo que resultará en préstamos incobrables para el banco.

Los bancos tienen fondos limitados, por lo tanto, al prestar, los bancos deben considerar si hay una manera de asignar sus reservas para satisfacer la demanda máxima de cada usuario, es decir, el préstamo que cumple con el límite de crédito máximo de cada usuario.

Por ejemplo, suponga que el banco tiene 12,000 fondos líquidos, y en este momento, tres personas A, B y C solicitan un préstamo.

El límite de crédito es de 4.000 yuanes.

El límite de crédito B es de 6000 yuanes

C límite de crédito es de 10.000 yuanes

Los requisitos del préstamo son:

Una solicitud de 2000 yuanes

B aplicación 4000 yuanes

C aplicación 3000 yuanes

Si el banco acepta y presta todo de una vez, solo le quedarán 3.000 yuanes de liquidez. Si C continúa solicitando los 7.000 yuanes restantes, el banco no tendrá dinero para depositar. El fracaso empresarial de C hizo que el banco enfrentara el riesgo de 3.000 yuanes en deudas incobrables.

Si el banco solo aprueba los requisitos de A y B, le quedarán 6,000 yuanes de liquidez. No importa si A solicita la cuota restante de 2.000 yuanes o B solicita la cuota restante de 2.000 yuanes, el banco puede cumplirla. Entonces A y B pueden completar con éxito el pago de la tarea. Después de esperar que A y B completen la tarea y paguen, luego apruebe la solicitud de C, de modo que la liquidez restante del banco sea de 9,000 yuanes, lo que puede cumplir con el requisito de cuota de C 7,000 yuanes restante, y respaldar con éxito a C para completar el negocio.

En otras palabras, al revisar los requisitos del préstamo, el banco debe considerar si el capital de trabajo restante puede ayudar a todos los usuarios que ya han prestado a obtener el monto máximo del préstamo si están de acuerdo con el préstamo . Es decir, cada vez que se revisa el préstamo, el banco debe considerar si el préstamo lo pondrá en un estado inseguro .

De esta manera, aunque el límite de crédito de todos no excederá la liquidez total del banco, el límite de crédito total de todos será mucho mayor que la liquidez total del banco, que es el apalancamiento . Y bajo el apalancamiento, cada préstamo se revisa cuidadosamente para asignar recursos dinámicamente, a fin de evitar que los fondos caigan en el punto muerto del prestamista (el banco se presta el uno al otro después de esperar que el otro pague la deuda ).

La crisis de las hipotecas de alto riesgo de 2007 en los Estados Unidos fue un ejemplo de un error algorítmico que condujo a un punto muerto. Muchas compañías e individuos no pudieron pagar préstamos y llevaron a la bancarrota a un gran número de bancos.

El algoritmo de evitación dinámica significa que cada vez que se realiza la asignación de recursos, debe calcularse cuidadosamente para garantizar que la aplicación del recurso no hará que el sistema entre en un estado inseguro. El estado seguro significa que podemos encontrar un método y una secuencia de asignación de recursos para que cada subproceso en ejecución pueda obtener los recursos que necesita. Si la asignación de recursos hará que el sistema entre en un estado inseguro, se rechaza. La evasión dinámica es un medio para evitar un punto muerto en la asignación de recursos.

De hecho, muy pocos programas adoptan una estrategia de evasión dinámica. La primera razón es la complejidad del algoritmo. Necesitamos mantener información como el uso de recursos y la cantidad de recursos que posee el hilo y la cantidad de recursos requeridos. La segunda razón es que nos resulta difícil predecir de antemano cuántos recursos necesita cada hilo; La razón es que si hay una gran cantidad de subprocesos, el cálculo cada vez que se asigna un recurso llevará mucho tiempo.

5.2 Evitación estática, evitar el punto muerto del código de tarea

En la Sección 5.1, discutimos la estrategia para evitar dinámicamente el punto muerto a partir de la asignación de recursos.

1. Eliminar las condiciones no preventivas. Convertimos los recursos en bienes preferentes, y los filósofos pueden tomar palillos unos de otros. Esta estrategia parece factible, pero no es universal. Por ejemplo, si el recurso preferente no es un palillo sino un candado, entonces el candado perderá su semántica original. ¡Estas consecuencias son impensables!

2. Eliminar la espera en espera. Este método es factible: si el filósofo no solicita los palillos, los dejará en la mano y se irá a dormir. Los palillos, ya sea que duerman y esperen a que otros filósofos se despierten cuando dejen los palillos), los filósofos recibirán dos palillos en secuencia e irán a cenar.

3. En la sección anterior, discutimos el uso de algoritmos bancarios para la asignación dinámica de recursos. Es factible usarlo para resolver problemas de filósofos, pero el algoritmo será más complicado. Resolveremos este problema desde la perspectiva de la asignación de recursos desde otro ángulo. La razón del punto muerto es que, desde una perspectiva de recursos, si cinco filósofos recogen un palillo al mismo tiempo, no habrá palillos en la mesa y ningún filósofo podrá comer. Si solo permitimos que hasta cuatro filósofos recojan palillos al mismo tiempo, entonces al menos uno de los cuatro filósofos puede obtener suficientes palillos para comer (queda un palillo en la mesa) y el punto muerto no ocurrirá.

Esta solución en realidad pertenece al algoritmo del banquero, porque cuando los cuatro filósofos recogen los palillos, solo quedará un palillo sobre la mesa. El quinto filósofo trató de recoger palillos chinos. Consideramos que si se le permitía recoger palillos chinos, los recursos restantes no podrían satisfacer a ningún filósofo que recogiera dos palillos chinos y los palillos chinos para comer, y el túnel rechazó su pedido.

Porque solo hay dos roles en esta pregunta, palillos y filósofo. Es decir, solo hay un recurso (palillos chinos), por lo que la relación de dependencia es relativamente simple y podemos estátizar el algoritmo del banquero.

4. Elimine la condición de espera de bucle. Como en el ejemplo en el tercero, estipulamos que todos los hilos que necesitan A y B necesitan obtener A antes de obtener B, entonces el punto muerto no ocurrirá. Debido a que no habrá una situación en la que un hilo contenga B y espere a A, no habrá ningún ciclo en espera. Para el problema de la comida del filósofo, también podemos romper el ciclo de espera especificando el orden en que se toman los palillos. Por ejemplo, podemos numerar filósofos: los filósofos de números impares primero deben tomar los palillos de la izquierda, y los filósofos de números pares primero deben tomar los palillos de la derecha, como se muestra en la siguiente figura:

 Sección 6 Tratamiento integral del punto muerto

En las secciones anteriores, presentamos la definición de punto muerto, las condiciones bajo las cuales se produce el punto muerto y cómo evitarlo.

Para las cuatro condiciones necesarias para que se produzca el punto muerto: recursos limitados, los recursos no se pueden adelantar, esperar en espera y esperar en bucle, siempre que rompamos alguno de ellos, el punto muerto no ocurrirá.

Las cosas no parecen complicadas, pero el hecho es que incluso los programadores experimentados no pueden evitar por completo los puntos muertos cuando realizan múltiples programaciones.

La razón principal es que cuando aumenta el número de recursos y subprocesos, es difícil determinar sus dependencias. Debemos descubrir y administrar la situación de punto muerto desde todas las dependencias posibles, lo cual es difícil de hacer en la programación real (excepto en casos simples).

Por ejemplo, el problema de la comida del filósofo, las primitivas PV (sincronización, exclusión mutua) pueden ser muy simples:

P(leftChopsticks)
    P(rightChopsticks)
       eat();
    V(rightChopsticks)
V(leftChopsticks)

Pero en el caso donde los filósofos (hilos) se ejecutan alternativamente, hay muchas posibilidades para sus dependencias instantáneas.

Además de diseñar considerando la asignación de recursos, el acceso secuencial a los recursos y las esperas sin retención, tratamos de evitar los puntos muertos tanto como sea posible. Cuando se producen puntos muertos, primero debemos proteger el sitio y realizar investigaciones. De).

Podemos ver el vmid del proceso Java que necesita ser visto a través del comando jps:

Luego verifique la pila en el proceso a través de jstack:

Tire hacia abajo, la información que necesitamos está a continuación:

Se puede ver que el jvm encontró un punto muerto y se produjo una espera circular entre Thread-0 y Thread-1.

También puede usar el comando jconsole para ver:

Haga clic en "Detectar punto muerto":

Luego puede ver el estado del hilo de interbloqueo:

1858706-20191208222011992-1857812293.pnguploading.4e448015.gifTransferencia fallida, re-carga cancelada1858706-20191208222011992-1857812293.pnguploading.4e448015.gif Transferencia fallida,re-cargacancelada1858706-20191208222011992-1857812293.pnguploading.4e448015.gif Transferencia fallida, re-carga cancelada

Publicado 59 artículos originales · Me gusta46 · Visitas 30,000+

Supongo que te gusta

Origin blog.csdn.net/sinat_41852207/article/details/105637099
Recomendado
Clasificación