Sistemas operativos modernos
Tal vez usted está pensando que las operaciones wait y signal se parecen a sieep y wakeup, y ya vimos que éstas tienen condiciones de competencia fatales. S í son muy similares, pero con una diferencia crucial: sIeep y wakeup fallaron porque mientras un proceso estaba tratando de desactivarse, otro estaba tratando de activarlo. Con los monitores, eso no puede suceder. La ex clusión mutua automática en los procedimientos de monitor garantiza que si el productor, por ejemplo, está en un procedimiento de monitor y descubre que el búfer está lleno, podrá terminar la operación wait sin tener que preocuparse por la posibilidad de que el calendarizador conmute hacia el consumidor justo antes de que wait termine. El consumidor ni siquiera podrá entrar en el monitor antes de que wait termine y que el productor se haya marcado como no ejecutable pro visionalmente. Aunque Pascal Simple es un lenguaje imaginario, algunos lenguajes de programación rea les manejan monitores, aunque no siempre en la forma diseñada por Hoare y Brinch Hansen. Uno de esos lenguajes es Java, que es un lenguaje orientado a objetos que maneja subprocesos en el nivel de usuario y también permite agrupar métodos (procedimientos) en clases. Si agre ga la palabra clave synchronized a una declaración de método, Java garantiza que una vez que un subproceso haya comenzado a ejecutar ese método, no se permitirá a ningún otro subpro ceso comenzar a ejecutar ningún otro método synchronized de esa clase. En la figura 2-28 se presenta una solución del problema del productor-consumidor utilizan do monitores en Java. La solución consiste en cuatro clases. La clase exterior, ProductorConsu- midor, crea y pone en marcha dos subprocesos, y c. La segunda y tercera clases, productor y consumidor, contienen el código del productor y el del consumidor. Por último, la clase mi_mo- nitor es el monitor, con dos subprocesos sincronizados que sirven para insertar y sacar elemen tos del búfer compartido. A diferencia de los ejemplos anteriores, aquí sí mostramos el código completo para insertar y quitar. Los subprocesos productor y consumidor son funcionalmente idénticos a sus contrapartes en todos nuestros ejemplos anteriores. El productor tiene un ciclo infinito que genera datos y los coloca en el búfer común. El consumidor tiene un ciclo infinito igual que saca datos del búfer común y hace algo divertido con ellos. La parte interesante de este programa es la clase mijnonitor, que contiene el búfer, las va riables de administración y dos métodos sincronizados. Cuando el productor está activo dentro de insertar, tiene la certeza de que el consumidor no puede estar activo dentro de quitar, y puede ac tualizar las variables y el búfer sin temor a que se presenten condiciones de competencia. La va riable cuenta lleva la cuenta del número de elementos que hay en el búfer, y puede adoptar cualquier valor a partir de O, incluyendo N - \ . La variable baja es el índice de la ranura del búfer de la cual se obtendrá el siguiente elemento. Asimismo, alta es el índice de la ranura donde se co locará el siguiente elemento. Está permitido que baja = alta, lo que implica que hay O, o bien, N elementos en el búfer; el valor de cuenta indica de cuál de los dos casos se trata. Los métodos sincronizados de Java difieren de los monitores clásicos en un aspecto fun damental: Java no maneja variables de condición. En vez de eso, ofrece dos procedimientos, wait y notify, que son el equivalente de sieep y wakeup sólo que cuando se usan dentro de mé todos sincronizados, no están sujetos a condiciones de competencia. En teoría, el método wait puede interrumpirse, y es de eso precisamente de lo que se traía el código que lo rodea. Java exige que el manejo de excepciones sea explícito.
RkJQdWJsaXNoZXIy MjI4NDcx