Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
Concurrente
ndice
1.
INTRODUCCIN........................................................................................................................1
2.
3.
4.
5.
6.
7.
8.
9.
EJERCICIOS ............................................................................................................................16
ndice de Figuras
Figura 2.1:
Figura 2.2:
Figura 4.1:
Programa y procesos.______________________________________________________2
Un programa dando lugar a ms de un proceso. _________________________________3
Concurrencia.____________________________________________________________5
Figura 4.2:
Figura 4.3:
Figura 4.4:
Figura 4.5:
Figura 5.1:
Figura 6.1:
Figura 6.2:
Figura 6.3:
Figura 7.1:
Figura 7.2:
Figura 7.3:
Figura 7.4:
Figura 8.1:
ii
Programacion Concurrente
1. Introduccin
Los primeros programas concurrentes fueron los propios Sistemas Operativos de multiprogramacin
en los que un solo procesador de gran capacidad deba repartir su tiempo entre muchos usuarios. Para
cada usuario, la sensacin era que el procesador estaba dedicado para l. Durante la dcada de los sesenta
y setenta esto fue as. La programacin de sistemas con capacidades de concurrencia se haca a bajo nivel,
en ensamblador, pues aparte de no disponer de lenguajes de alto nivel con capacidades de concurrencia,
se primaba la supuesta eficiencia del cdigo escrito directamente en ensamblador. La aparicin en 1972
del lenguaje de alto nivel Concurrent Pascal [Brinch-Hansen, 1975], desarrollado por Brinch Hansen, se
encarg de romper este mito y abrir la puerta a otros lenguajes de alto nivel que incorporaban
concurrencia.
Desde entonces la programacin concurrente ha ido ganando inters y actualmente se utiliza muy a
menudo en la implementacin de numerosos sistemas. Tres grandes hitos se nos antojan importantes para
que la programacin concurrente actualmente sea tan importante:
La aparicin del concepto de thread o hilo que hace que los programas puedan ejecutarse con
mayor velocidad comparados con aquellos que utilizan el concepto de proceso.
MGB
Programacion Concurrente
ese navegador, cada uno de ellos navegando por un sitio diferente. Cada instancia del programa es un
proceso. Cada proceso tendr su propio contador de programa, as como sus propios registros, pila y
variables.
En la Figura 2.1: puede observarse el ejemplo mencionado donde existe un programa almacenado en
disco y tres instancias de ese programa ejecutndose. Son tres procesos, cada uno con su propia
informacin.
Proceso p1
Proceso p2
Proceso p3
SO
Navegador Internet
Figura 2.1:
Programa y procesos.
2.2. Concurrencia
Dos procesos sern concurrentes cuando la primera instruccin de uno de ellos se ejecuta despus de
la primera instruccin del otro y antes de la ltima. Es decir, existe un solapamiento en la ejecucin de sus
instrucciones. No tienen por qu ejecutarse exactamente al mismo tiempo, simplemente es suficiente con
el hecho de que exista un intercalado entre la ejecucin de sus instrucciones. Si se ejecutan al mismo
tiempo los dos procesos, entonces tenemos una situacin de programacin paralela. La programacin
concurrente es un paralelismo potencial. Depender del hardware subyacente como veremos ms
adelante.
De esta forma, en la figura 2.1 tendramos tres procesos concurrentes si se diese la circunstancia
anterior. Se trata de un primer nivel de concurrencia, donde existen 3 procesos independientes
ejecutndose al mismo tiempo sobre el SO. Cada proceso corresponde a una instancia de un programa.
Sin embargo, esto slo es una parte de la verdad. No necesariamente un proceso tiene por qu ser todo
el programa en ejecucin sino que puede ser parte de l. Dicho de otra forma, un programa, al ponerse en
ejecucin, puede dar lugar a ms de un proceso, cada uno de ellos ejecutando una parte del programa.
Continuando con el miso ejemplo, el programa de navegador de Internet puede dar lugar a ms de un
proceso: uno que controla las acciones del usuario con la interfaz, otro que hace las peticiones al servidor,
etc. De esta forma, la Figura 2.1 se convertira en la figura 2.2, suponiendo que se crean dos procesos
cada vez que se ejecuta el programa. Todos estos procesos tambin pueden ejecutarse concurrentemente.
MGB
Programacion Concurrente
p1.1
p1.2
p2.1
p2.2
p3.1
p3.2
SISTEMA OPERATIVO
navegador
Internet
Figura 2.2:
Una definicin bastante extendida es que un proceso es un programa en ejecucin, pero no es muy
exacto pues realmente un programa puede estar compuesto por diversos procesos. Un SO no deja de ser
un programa con varios procesos que se ejecutan al mismo tiempo.
Cuando varios procesos se ejecutan concurrentemente puede haber procesos que colaboren para un
determinado fin mientras que puede haber otros que compitan por los recursos del sistema. Incluso
aquellos procesos que colaboran debern competir a la hora de obtener tiempo de procesador. Por
ejemplo, en la Figura 2.2:, p1.1 y p1.2 pueden estar colaborando para hacerle la vida ms fcil al usuario
mientras que p1.2 y p2.2 pueden estar compitiendo para acceder al disco.
Para llevar a cabo las tareas de colaboracin y competencia por los recursos se hace necesaria la
introduccin de mecanismos de comunicacin y sincronizacin entre procesos. Del estudio de estos
mecanismos trata la programacin concurrente.
MGB
Programacion Concurrente
a uno de las distintas estancias. Podra ocurrir que al llegar a capturar los datos de la ltima estancia, la
primera ya haya sido pasto de las llamas. Tanto la captura de datos desde cada estancia como su
tratamiento y posterior actuacin son candidatos a ser procesos distintos y de naturaleza concurrente. Esto
nos garantiza que nuestro sistema de control pueda responder a las alarmas que se produzcan.
3.2.4 Simulacin
Los programas secuenciales encuentran problemas al simular sistemas en los que existen objetos
fsicos que tienen un comportamiento autnomo independiente. La programacin concurrente permitir
modelar esos objetos fsicos y ponerlos en ejecucin de forma independiente y concurrente,
sincronizndolos de la forma apropiada.
3.2.5 SGBD
En Sistemas Gestores de Bases de Datos la concurrencia juega un papel muy importante cuando se va
a permitir a varios usuarios interactuar con el sistema. Cada usuario puede ser visto como un proceso.
Obviamente hay que implementar la poltica adecuada para evitar situaciones en las que dos usuarios
modifican al mismo tiempo un registro. Sin embargo, a varios usuarios que quieran acceder a un mismo
registro para consultarlo y no modificarlo, debe permitrseles un acceso concurrente.
MGB
Programacion Concurrente
P1
P2
P3
Figura 4.1:
Concurrencia.
Aparte de la situacin en la que un proceso puede aprovechar ciclos de CPU mientras otro proceso
hace operaciones de entrada/salida, existen otros posibles beneficios del uso de concurrencia en sistemas
monoprocesador:
La posibilidad de proporcionar un servicio interactivo a mltiples usuarios. Este sera el caso por
ejemplo de un Sistema Operativo multiusuario ejecutndose sobre una mquina monoprocesador.
La posibilidad de dar una solucin adecuada a problemas que son de naturaleza eminentemente
concurrente tal y como se mencion en la seccin 3.2.
Variable
compartida
escribe
MEMORIA comn a
todos los procesos
lee
proceso
A
proceso
B
proceso
C
SISTEMA OPERATIVO
procesador
Figura 4.2:
MGB
Programacion Concurrente
P1
P2
P3
Figura 4.3:
Paralelismo.
Sin embargo, y siendo realistas, lo normal en un sistema concurrente es tener ms procesos que
procesadores por lo que, de alguna forma, tiene que haber algn esquema de multiprogramacin en uno o
ms procesadores.
Sistemas fuertemente acoplados: tanto los procesadores como otros dispositivos (incluida la
memoria) estn conectados a un bus. Esto permite que todos los procesadores puedan compartir la
misma memoria. Puede ocurrir que cada procesador tenga su propia memoria local, pero la
sincronizacin y comunicacin entre procesos se har mediante variables situadas en la memoria
compartida, es decir, mediante variables compartidas (4.4).
Sistemas dbilmente acoplados: aqu no existe una memoria compartida por los procesadores.
Cada procesador tiene su propia memoria local y est conectado con otros procesadores mediante
algn tipo de enlace de comunicacin. Un tipo especial de estos sistemas lo constituyen los
sistemas distribuidos, que estn formados por un conjunto de nodos distribuidos geogrficamente
y conectados de alguna forma. Estos nodos pueden ser a su vez mono o multiprocesador. El
sistema distribuido por antonomasia es Internet.
nodo
B
Variable
compartida
MEMORIA comn a
todos los procesos
paso de mensaje
escribe
lee
proceso
A
procesador
proceso
B
proceso
C
nodo
A
nodo
C
SISTEMA OPERATIVO
procesador
procesador
procesador
procesador
procesador
Figura 4.5:
Figura 4.4:
procesador
Sistema distribuido.
MGB
Programacion Concurrente
uso de paso de mensaje tal y como se aprecia en la Figura 4.5:. El paso de mensaje no slo es aplicable a
los sistemas distribuidos sino que tambin puede usarse en sistemas de multiproceso y de
multiprogramacin. Es por esta razn por la que actualmente los mecanismos de paso de mensaje son ms
utilizados en los lenguajes concurrentes, aparte de la buena sintona que este mecanismo guarda con la
Programacin Orientada a Objetos. No en vano, la unin de ambos paradigmas, concurrente y objetos, ha
dado lugar a lo que se conoce como Programacin Concurrente Orientada a Objetos. El lenguaje Java no
deja de ser un ejemplo.
Para terminar este apartado es bueno dejar claras algunas definiciones adicionales que a veces llevan a
confusin y en las que no todos los autores pueden estar de acuerdo:
un programa concurrente define un conjunto de acciones que pueden ser ejecutadas
simultneamente
un programa paralelo es un tipo de programa concurrente diseado para ejecutarse en un
sistema multiprocesador
un programa distribuido es un tipo de programa paralelo que est diseado para ejecutarse en
un sistema distribuido, es decir, en una red de procesadores autnomos que no comparten una
memoria comn
Nos ocuparemos de los programas concurrentes, no haciendo ningn tipo de suposicin sobre el
nmero de procesadores y su topologa. Un programa concurrente debe funcionar independientemente de
que lo ejecutemos en un sistema monoprocesador o en un sistema multiprocesador, ya sea ste fuerte o
dbilmente acoplado.
5. Ejecucin concurrente
Una vez que sabemos qu es un programa concurrente y las distintas arquitecturas hardware que
pueden soportarlo, es el momento de ver qu partes de un programa se pueden ejecutar concurrentemente
y qu partes no, y cmo especificarlo en un lenguaje de programacin.
Est claro que la primera sentencia se debe ejecutar antes de la segunda. Consideremos ahora el
siguiente fragmento:
x := 1 ;
y := 2 ;
z := 3 ;
Ahora, el orden en que se ejecuten no interviene en el resultado final. Si tuviramos tres procesadores
se podran ejecutar cada lnea en un procesador y as incrementaramos la velocidad del sistema.
L(Sk) = {a1, a2, ..an}, como el conjunto de lectura del conjunto de instrucciones Sk y que
est formado por todas las variables cuyos valores son referenciados (se leen) durante la
ejecucin de las instrucciones en Sk.
E(Sk) = {a1, a2, ..an}, como el conjunto de escritura del conjunto de instrucciones Sk y que
est formado por todas las variables cuyos valores son referenciados (se escriben) durante la
ejecucin de las instrucciones en Sk.
Para que dos conjuntos de instrucciones Si y Sj se puedan ejecutar concurrentemente, se tiene que
cumplir que:
Programacion Concurrente
1.
L( S i ) E ( S j ) =
2.
E ( S i ) L( S j ) =
3.
E (Si ) E (S j ) =
E(S1) = {a}
L(S2) ={z}
E(S2) = {b}
L(S3) ={a, b}
E(S3) = {c}
L(S4) ={c}
E(S4) = {w}
Entre S1 y S2:
Entre S1 y S3:
L( S1 ) E ( S 2 ) =
L( S1 ) E ( S 3 ) =
E ( S1 ) L( S 2 ) =
E ( S1 ) L( S 3 ) = a
E ( S1 ) E ( S 2 ) =
E ( S1 ) E ( S 3 ) =
Entre S1 y S4:
Entre S2 y S4:
L( S1 ) E ( S 4 ) =
L( S 2 ) E ( S 4 ) =
E ( S1 ) L( S 4 ) =
E ( S 2 ) L( S 4 ) = a
E ( S1 ) E ( S 4 ) =
E(S2 ) E(S4 ) =
Entre S2 y S3:
Entre S3 y S4:
L( S 2 ) E ( S 3 ) =
L( S 3 ) E ( S 4 ) =
E ( S 2 ) L( S 3 ) = b
E ( S 3 ) L( S 4 ) = c
E (S 2 ) E(S3 ) =
E (S3 ) E (S 4 ) =
De todo esto se deduce la siguiente tabla en la que puede verse qu pares de sentencias pueden
ejecutarse de forma concurrente:
Programacion Concurrente
S1
S2
Si
S1
S2
S3
S4
No
Si
No
Si
No
S3
S4
Una vez que sabemos qu se puede y qu no se puede ejecutar concurrentemente, se hace necesario
algn tipo de notacin para especificar qu partes de un programa pueden ejecutarse concurrentemente y
qu partes no.
S1
S2
S3
S4
Figura 5.1:
Grafo de precedencia.
begin
cobegin
a := x + y ;
b := z + 1 ;
coend
c := a b;
w := c + 1 ;
end
Programacion Concurrente
Las instrucciones dentro del par cobegin/coend pueden ejecutarse en cualquier orden, mientras que el
resto se ejecuta de manera secuencial.
i1
i2
i2
programa
i3
i4
i5
i6
i4
i7
i5
Figura 6.1:
Orden total.
i1
i3
i6
i7
Figura 6.2:
i2
i4
i5
i1
i3
i6
i7
Orden parcial.
En los programas concurrentes, sin embargo, hay un orden parcial. Ante el mismo conjunto de datos
de entrada no se puede saber cul va a ser el flujo de ejecucin. En cada ejecucin del programa el flujo
puede ir por distinto sitio. En la figura 6.2, donde se supone que todas las instrucciones pueden ejecutarse
concurrentemente, podemos ver cmo en dos ejecuciones distintas el orden en el que se ejecutan las
instrucciones puede variar.
En la Figura 6.3 podemos observar el grafo de precedencia y el cdigo con el par cobegin/coend para
el caso de la Figura 6.2.
i1
i2
i3
i4
i5
Figura 6.3:
i6
i7
begin
cobegin
i1; i2; i3; i4; i5; i6; i7;
coend;
end.
6.1.2 Indeterminismo
Este orden parcial lleva a que los programas concurrentes puedan tener un comportamiento
indeterminista, es decir, puedan arrojar diferentes resultados cuando se ejecutan repetidamente sobre el
mismo conjunto de datos de entrada. Esto suele llevar a muchas sorpresas cuando uno se inicia en la
programacin concurrente.
10
Programacion Concurrente
Consideremos el siguiente programa en el que dos procesos se ejecutan concurrentemente para sumar
1 a la variable x. Esa variable x es compartida por ambos procesos pues ha sido declarada como global.
La sintaxis utilizada es la del lenguaje Pascal-FC.
program Incognita;
var x: integer;
process P1;
var i: integer;
begin
for i:=1 to 5 do x:=x+1;
end;
begin
x:=0;
cobegin
P1;
P2;
coend;
end.
process P2;
var j: integer;
begin
for j:=1 to 5 do x:=x+1
end;
Qu valor tendr la variable x al terminar el programa? Todo hace pensar que el valor debera ser 10.
Sin embargo, el valor de x puede ser 5, 6, 7, 8, 9 10.
Esta caracterstica hace muy difcil la labor de depuracin en los programas concurrentes. Podemos
ejecutar el programa 1.000 veces y podra dar como resultado 10 y al ejecutarlo 1.001 veces nos podra
dar 8.
Intuitivamente podemos ver que el error se encuentra en el acceso incontrolado a una variable
compartida por parte de 2 procesos. En la siguiente seccin vemos ms a fondo la raz del problema.
7. Problemas
concurrente
inherentes
la
programacin
Dos son bsicamente los problemas con los que nos vamos a encontrar a la hora de confeccionar un
programa concurrente: el problema de la exclusin mutua y el de la condicin de sincronizacin.
P1
P2
(1) LOAD X R1
(1) LOAD X R1
(2) ADD R1 1
(2) ADD R1 1
(3) STORE R1 X
(3) STORE R1 X
Cada una de estas instrucciones es atmica o indivisible, es decir, se va a ejecutar en un ciclo de reloj
del procesador sin poder ser interrumpidas. Puesto que hemos dicho que en programacin concurrente
existe un orden parcial, cualquier intercalado entre estas instrucciones es vlido. En la Figura 7.1: puede
verse una traza para un intercalado particular de estas seis lneas de cdigo en el que el valor final de la
variable x no es el esperado. Se ha perdido un incremento. Si tenemos en cuenta que estas lneas de
11
Programacion Concurrente
cdigo estn en un bucle ahora podremos entender por qu son posible resultados menores de 10 para la
variable x. Todo depender del nmero de incrementos perdidos, que en cada ejecucin puede ser distinto
e incluso no producirse.
P1
P2
3
1
Tiempo
Figura 7.1:
P1
P2
x:=x+1
Figura 7.2:
P1
Seccin crtica
P2
x:=x+1
Figura 7.3:
Seccin crtica
La programacin concurrente deber ofrecernos mecanismos para especificar qu partes del cdigo
han de ejecutarse en exclusin mutua con otras partes.
12
Programacion Concurrente
cmara
impresora
LECTOR
GESTOR
buffer
Figura 7.4:
IMPRESOR
cola de impresin
process gestor;
begin
begin
repeat
repeat
captura imagen;
almacena en buffer;
trata imagen;
forever
end;
process impresor;
begin
repeat
coge imagen de cola;
imprime imagen;
forever
end;
end;
El lector debera apreciar que la solucin al problema est incompleta. Debera tratar de responder a
las siguientes preguntas:
Qu ocurre cuando el proceso lector o el proceso gestor tratan de poner una imagen y el buffer o
la cola estn llenos?
Qu ocurre cuando el proceso gestor o el proceso impresor tratan de coger una imagen y el
buffer o la cola estn vacos?
Hay situaciones en las que un recurso compartido por varios procesos, como puede ser el buffer o la
cola de impresin en nuestro ejemplo, se encuentra en un estado en el que un proceso no puede hacer una
determinada accin con l hasta que no cambie su estado. A esto se le denomina condicin de
sincronizacin.
La programacin concurrente ha de proporcionarnos mecanismos para bloquear procesos que no
puedan hacer algo en un momento determinado a la espera de algn evento (Ej. que el buffer deje de estar
vaco), pero tambin que permita desbloquearlos cuando ese evento haya ocurrido.
Para entender en qu consisten estas propiedades, consideremos el famoso juego del pauelo en el que
hay dos equipos, A y B, y un juez con un pauelo (Figura 8.1:). Cada jugador de un equipo tiene un
nmero del 1 al 3. No puede haber dos jugadores en el mismo equipo con el mismo nmero. El juez dice
13
Programacion Concurrente
un nmero y entonces los dos rivales con el mismo nmero salen corriendo a coger el pauelo. El jugador
que lo coja ha de volver corriendo a su sitio sin que su rival logre tocarle la espalda.
En este escenario explicaremos las distintas propiedades de vivacidad y seguridad.
el 2
Figura 8.1:
Exclusin mutua. Hay recursos en el sistema que deben ser accedidos en exclusin mutua tal y
como hemos visto anteriormente. Cuando esto ocurre, hay que garantizar que si un proceso adquiere
el recurso, otros procesos debern esperar a que sea liberado. De lo contrario, el resultado puede ser
imprevisto. En nuestro ejemplo, el pauelo ha de adquirirse en exclusin mutua, o lo coge un jugador
o lo coge otro. Si lo cogen los dos a la vez puede llegar a romperse, llevando a un malfuncionamiento
del sistema.
Condicin de sincronizacin. Hay situaciones en las que un proceso debe esperar por la ocurrencia
de un evento para poder seguir ejecutndose. Cuando esto ocurre, hay que garantizar que el proceso
no prosigue hasta que no se produce el evento. De lo contrario, el resultado puede ser imprevisto. En
nuestro ejemplo, un jugador ha de esperar a que digan su nmero para poder salir corriendo. Si sale
corriendo antes llevara a un malfuncionamiento del sistema.
Interbloqueo. Se produce una situacin de interbloqueo cuando todos los procesos estn esperando
porque ocurra un evento que nunca se producir. Hay que garantizar que no se producen este tipo de
situaciones. En nuestro ejemplo se producira si un jugador se guarda el pauelo y se va para su casa.
El juez esperara porque le devolvieran el pauelo y los jugadores esperaran porque el juez dijese su
nmero, pero ninguno de estos eventos va a ocurrir nunca. Se suele conocer tambin con el nombre
de deadlock o abrazo mortal.
Interbloqueo activo: El anterior interbloqueo tambin suele conocerse como pasivo. Se produce una
situacin de interbloqueo activo cuando un sistema ejecuta una serie de instrucciones sin hacer
ningn progreso. Hay que garantizar que no ocurra este tipo de situaciones. En nuestro ejemplo se
producira si dos jugadores, al intentar coger el pauelo, amagan una y otra vez, pero no se deciden a
cogerlo. Mientras que la deteccin de un intebloqueo pasivo es ms o menos simple, la deteccin de
un interbloqueo activo es muy complicada. Se suele conocer tambin con el nombre de livelock. A
partir de ahora cada vez que hablemos de interbloqueo nos referiremos al interbloqueo pasivo.
Inanicin: Se produce una situacin de este tipo cuando el sistema en su conjunto hace progresos,
pero existe un grupo de procesos que nunca progresan pues no se les otorga tiempo de procesador
para avanzar. En nuestro ejemplo podra darse si el juez nunca dice el nmero de un jugador en
concreto. Hay que garantizar que haya una cierta equidad en el trato a los procesos a no ser que las
especificaciones del sistema digan lo contrario. Se trata de un problema tambin difcil de detectar.
Su suele conocer tambin con el nombre de starvation.
14
Programacion Concurrente
Resumen
En el presente captulo se han presentado los conceptos fundamentales de la programacin
concurrente. Se ha definido el concepto de proceso, de concurrencia y de programacin concurrente. Se
han visto las distintas plataformas
hardware donde poder ejecutar programas concurrentes:
monoprocesador y multiprocesador y, en funcin de ello, se ha visto la diferencia por un lado entre
multiprogramacin, multiproceso y procesamiento distribuido y, por otro lado, entre programas
concurrentes, paralelos y distribuidos. El hecho de que dos procesos sean concurrentes no implica
necesariamente que se ejecuten exactamente al mismo tiempo. Eso depender del hardware subyacente.
En cualquier caso, e independientemente del hardware, los beneficios de la programacin concurrente
pueden resumirse en: mayor velocidad de ejecucin, mejor aprovechamiento de la CPU y soluciones
ptimas a problemas de naturaleza eminentemente concurrente.
Tambin se ha visto en este captulo cmo determinar cundo un conjunto de instrucciones puede
ejecutarse de manera concurrente mediante las condiciones de Bernstein. Una vez determinado qu se
puede ejecutar concurrentemente, hemos visto cmo especificarlo de dos formas distintas: mediante el par
cobegin/coend y mediante grafos de precedencia.
Los programas concurrentes se caracterizan por un orden parcial en la ejecucin de sus instrucciones
frente al orden total presente en los programas secuenciales. Este orden parcial nos lleva a un
indeterminismo en el resultado arrojado por la ejecucin de los programas concurrentes. Este
indeterminismo hace que la depuracin y correccin de programas concurrentes no sea una tarea
precisamente trivial.
Dos son los grandes problemas a resolver en problemas de naturaleza concurrente: el problema de la
exclusin mutua y el problema de la condicin de sincronizacin. Un programa concurrente ser correcto
si, adems de contemplar sus especificaciones funcionales donde irn implcitas condiciones de exclusin
mutua y de sincronizacin, es capaz de evitar que se produzcan situaciones de interbloqueo y de inanicin
de procesos.
15
Programacion Concurrente
9. Ejercicios
1.
S1
S2
S3
S4
S5
S6
S7
2.
3.
4.
Construir un programa concurrente que explote al mximo la concurrencia para copiar un fichero
f en un fichero g utilizando el par cobegin/coend.
Usando las condiciones de Bernstein, construir el grafo de precedencia del siguiente trozo de
cdigo y el programa concurrente correspondiente usando el par cobegin/coend.
S1: cuad := x*x;
S2: m1 := a*cuad;
S3: m2 := b*x;
S4: z := m1 + m2;
S5: y := z + c;
5.
16
Construir dos programas concurrentes que se correspondan con los de la siguiente figura
utilizando el par cobegin/coend.
Programacion Concurrente
S1
S1
S2
S3
S2
S5
S4
S3
S4
S5
S6
S7
S6
Cuestiones breves
1.
2.
3.
4.
5.
6.
7.
17