Concurrent Pascal es un lenguaje de programación diseñado por Per Brinch Hansen para escribir programas de computación concurrente como sistemas operativos y sistemas de monitoreo de computación en tiempo real en computadoras con memoria compartida . [1]
Se utiliza un lenguaje independiente, Sequential Pascal , como lenguaje para los programas de aplicaciones ejecutados por los sistemas operativos escritos en Concurrent Pascal. Ambos lenguajes son extensiones de Pascal de Niklaus Wirth y comparten un intérprete de código enhebrado común . [2] A continuación se describe en qué se diferencia Concurrent Pascal de Wirth.
Se eliminaron varias construcciones en Pascal de Concurrent Pascal por simplicidad y seguridad: [2]
Estas omisiones permiten garantizar, mediante una combinación de comprobaciones en tiempo de compilación y una comprobación mínima en tiempo de ejecución en el intérprete de código enhebrado, que un programa no pueda dañarse a sí mismo ni a otro programa al direccionarse fuera de su espacio asignado.
Pascal concurrente incluye tipos de datos de clase, monitor y proceso. Las instancias de estos tipos se declaran como variables y se inicializan en una init
instrucción.
Las clases y los monitores son similares: ambos incluyen variables y procedimientos privados con procedimientos públicos (llamados entradas de procedimiento). Una instancia de clase puede ser utilizada solo por un proceso, mientras que una instancia de monitor puede ser compartida por varios procesos. Los monitores proporcionan el único mecanismo para la comunicación entre procesos en un programa Pascal concurrente.
Solo se puede ejecutar un proceso a la vez dentro de una instancia de monitor dada. La cola, un tipo de datos integrado, junto con las operaciones delay
y continue
, se utilizan para la programación dentro de los monitores. Cada variable de tipo cola puede contener un proceso. Si se deben retrasar muchos procesos en un monitor, se deben proporcionar múltiples variables de cola, generalmente organizadas como una matriz. La variable de cola de proceso único le da a un monitor control total sobre la programación a mediano plazo, pero el programador es responsable de desbloquear el proceso correcto.
Un proceso, como una clase o un monitor, tiene variables locales, procedimientos y una sentencia inicial, pero no tiene entradas de procedimiento. La sentencia inicial normalmente se ejecuta indefinidamente, llamando a procedimientos locales, procedimientos de clase y procedimientos de monitor. Los procesos se comunican a través de procedimientos de monitor. Las reglas del lenguaje evitan los bloqueos imponiendo una jerarquía a los monitores. Pero nada puede evitar que un monitor olvide por error desbloquear un proceso retrasado (al no llamar a continue) de modo que el sistema pueda seguir colgándose de forma efectiva debido a errores de programación.
La configuración de los procesos, monitores y clases en un programa Pascal concurrente se establece normalmente al inicio de la ejecución y no se modifica posteriormente. Las rutas de comunicación entre estos componentes se establecen mediante variables que se pasan en las init
instrucciones, ya que las variables de instancia de clase y monitor no se pueden utilizar como parámetros de procedimiento.
El siguiente ejemplo muestra la declaración de un monitor simple y su uso por dos procesos que se comunican.
tipo "Monitor de buffer delimitado" buffer = Monitor var guardado : entero ; "el elemento guardado es un entero" fullq , emptyq : cola ; "usado solo por dos procesos" completo : booleano ; "verdadero si se guarda un elemento:" "Pone el elemento en el búfer" procedimiento entrada put ( elemento : Integer ); begin si está lleno entonces delay ( fullq ); "bloquear si está lleno" save : = elemento ; "guardar el elemento" full : = true ; "marcar como lleno" continue ( emptyq ) "desbloquear consumidor" end ; "Obtiene el elemento del buffer" procedimiento entrada get ( var item : Integer ); begin si no está lleno entonces delay ( emptyq ); "bloquea si está vacío" item : = guardado ; "obtiene el elemento" full : = false ; "marca como no lleno" continue ( fullq ) "desbloquea al productor" end ; "Inicializar el monitor" begin full : = false end ; "El productor usa un buffer" productor = proceso ( pass : Buffer ); var item : Integer ; begin ciclo "ejecutar en un bucle para siempre" "producir un elemento" pass . put ( item ) "pasar un elemento al monitor" end end ; "El consumidor usa un buffer" consumidor = proceso ( pasar : Buffer ); var elemento : Entero ; comenzar ciclo pasar . obtener ( elemento ); "obtener un elemento del monitor" "consumir el elemento" fin fin ;"declarar instancias del monitor, productor y consumidor" "dar al productor y consumidor acceso al monitor" var pass : Buffer ; prod : Productor ; cons : Consumidor ; begin init pass , "iniciar el monitor" prod ( pass ), "iniciar el proceso del productor" cons ( pass ) "iniciar el proceso del consumidor" end .