You are on page 1of 22

CAPTULO 1.

CONCEPTOS FUNDAMENTALES

1.1 Introduccin
La idea de programacin concurrente siempre estuvo asociada al mundo de los
Sistemas Operativos (SSOO). No en vano, 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.
La aparicin ms reciente de lenguajes como Java, lenguaje orientado a
objetos de propsito general que da soporte directamente a la programacin
concurrente mediante la inclusin de primitivas especficas.
La aparicin de Internet que es un campo abonado para el desarrollo y la
utilizacin de programas concurrentes. Cualquier programa de Internet en el
que podamos pensar tales como un navegador, un chat, etc, estn
programados usando tcnicas de programacin concurrente.

En lo que resta de captulo introduciremos el concepto de programacin


concurrente, los beneficios que reporta, el hardware en el que puede ejecutarse, la
forma de especificarlo en un lenguaje y las caractersticas, problemas y
propiedades de correccin de un programa concurrente.

1.2 Concepto de programacin concurrente


Segn el diccionario de la Real Academia Espaola, una de las acepciones de la
palabra concurrencia es
Acaecimiento o concurso de varios sucesos en un mismo tiempo.

M.E Carmen Cern G Programacin Concurrente BUAP 1


Si en esta definicin sustituimos la palabra suceso por proceso ya tenemos una
primera aproximacin a lo que va a ser la concurrencia en computacin.
Puesto que en la definicin anterior y en la que daremos posteriormente de
programacin concurrente aparece la palabra proceso y sta est basada en el
concepto de programa, se hace necesario dejar claro en este punto qu se va a
entender tanto por programa como por proceso.

1.2.1 Programa y proceso


Un programa es un conjunto de instrucciones. Es, simplemente, un texto que
consiste en una secuencia de lneas de cdigo que dicen qu hacer con un
conjunto de datos de entrada para producir algn tipo de salida. Se trata de algo
esttico. Puede compararse con el concepto de clase en el mbito de la
Programacin Orientada a Objetos (POO). Para que el programa pueda hacer
algo de verdad hay que ponerlo en ejecucin.
Una primera definicin incompleta de proceso sera la de un programa en
ejecucin. Es decir, un proceso es algo ms que las lneas de cdigo de un
programa. Un proceso es algo dinmico. Est representado por el valor del
contador de programa, el contenido de los registros del procesador, un pila y una
seccin de datos que contiene variables globales. Un proceso es una entidad
dinmica. Puede compararse con el concepto de objeto en el mbito de la POO.
De igual manera que en POO puede haber mltiples objetos de una clase
determinada, aqu puede haber mltiples procesos que corresponden al mismo
programa. Como ejemplo consideremos un servidor de aplicaciones donde reside
una aplicacin de navegador de Internet y existen varios usuarios ejecutando 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 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 proceso proceso


p1 p2 p3

SISTEMA OPERATIVO

navegador
Internet

Figura 1 Programa y procesos.

M.E Carmen Cern G Programacin Concurrente BUAP 2


1.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 1 tendramos tres procesos concurrentes si se diese
la circunstancia anterior. Se trata de un primer nivel de concurrencia1, donde
existen 3 procesos independientes ejecutndose al mismo tiempo sobre el
Sistema Operativo. 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 mismo 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 1 se
convertira en la Figura 2, suponiendo que se crean dos procesos cada vez que se
ejecuta el programa. Todos estos procesos tambin pueden ejecutarse
concurrentemente.

p1.1 p1.2 p2.1 p2.2 p3.1 p3.2

SISTEMA OPERATIVO

navegador
Internet

Figura 2 Un programa dando lugar a ms de un proceso.

As pues, una definicin ms acertada de proceso es la de una actividad


asncrona susceptible de ser asignada a un procesador. 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
Sistema Operativo no deja de ser un programa con varios procesos que se
ejecutan al mismo tiempo.

1
En el siguiente captulo se ver que existe un segundo nivel de concurrencia.

M.E Carmen Cern G Programacin Concurrente BUAP 3


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, 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 estas tareas de colaboracin y competencia por los recursos
se hace necesaria la introduccin de mecanismos de comunicacin y
sincronizacin entre procesos. Precisamente del estudio de estos mecanismos
trata la programacin concurrente.

1.2.3 Programacin Concurrente


La programacin concurrente es la disciplina que se encarga del estudio de las
notaciones que permiten especificar la ejecucin concurrente de las acciones de
un programa, as como las tcnicas para resolver los problemas inherentes a la
ejecucin concurrente, que son bsicamente comunicacin y sincronizacin.
Como puede intuirse, el trabajar con procesos concurrentes va a aadir
complejidad a la tarea de programar. Cabe entonces hacerse la pregunta de
cules son los beneficios que aporta la programacin concurrente?

1.3 Beneficios de la programacin concurrente


Existen diversos motivos por los que la programacin concurrente es til.
Destacaremos aqu dos de ellos: velocidad de ejecucin y solucin de problemas
de naturaleza concurrente. Otros beneficios adicionales como el mejor
aprovechamiento de la CPU saldrn a lo largo del captulo.

1.3.1 Velocidad de ejecucin


Cuando la puesta en ejecucin de un programa conlleva la creacin de varios
procesos y el sistema consta de ms de un procesador, existe la posibilidad de
asignar un proceso a cada procesador de tal forma que el programa se ejecuta de
una forma ms rpida. Los programas de clculo numrico son grandes
beneficiados de este hecho.

1.3.2 Solucin de problemas inherentemente concurrentes


Existen algunos problemas cuya solucin es ms fcil de abordar mediante el uso
de programacin concurrente pues su naturaleza es eminentemente concurrente.
Destacamos algunos de ellos, pero para una discusin ms detallada se sugiere
consultar [Bacon, 1998].

Sistemas de control
Son aquellos sistemas en los que hay una captura de datos, normalmente a travs
de sensores, un anlisis de esos datos y una posible actuacin posterior en
funcin del resultado del anlisis. La recoleccin de datos se puede estar haciendo
de diversas entidades fsicas como por ejemplo edificios o estancias dentro de
edificios. No sera tolerable un sistema secuencial que vaya capturando los datos

M.E Carmen Cern G Programacin Concurrente BUAP 4


uno 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.

Tecnologas web
La mayora de los programas relacionados con la web son concurrentes: los
servidores web que son capaces de atender concurrentemente mltiples
conexiones de usuarios; los programas de chat que permiten mantener la
conversacin de varios usuarios; los servidores de correo que permiten que
mltiples usuarios puedan mandar y recibir mensajes al mismo tiempo; los propios
navegadores que permiten que un usuario pueda estar haciendo una descarga
mientras navega por otras pginas, o se ejecuta un applet de Java, etc.

Aplicaciones basadas en interfaces de usuarios


La concurrencia en este tipo de aplicaciones va a permitir que el usuario pueda
interaccionar con la aplicacin aunque sta est realizando alguna tarea que
consume mucho tiempo de procesador. Un proceso controla la interfaz mientras
otro hace la tarea que requiere un uso intensivo de la CPU. Esto facilitar que
tareas largas puedan ser abortadas a mitad de ejecucin.

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.

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.

1.4 Concurrencia y arquitecturas hardware


Hasta ahora slo hemos hablado de procesos, es decir, de software. No hemos
dicho nada del hardware en el que se van a ejecutar nuestros procesos
concurrentes. Parece obvio pensar que sin dos procesos van a ejecutarse de
forma concurrente vamos a necesitar dos procesadores, uno para cada proceso.

M.E Carmen Cern G Programacin Concurrente BUAP 5


Sin embargo, esto no tiene por qu ser as. Depender, aunque no
exclusivamente, del hardware disponible y su topologa.
No es el propsito de este libro el hablar de hardware, pero s que es necesario
hacer una pequea incursin para posteriormente entender algunos conceptos.
Cuando hablamos de hardware nos estamos refiriendo fundamentalmente al
nmero de procesadores en el sistema. As, se puede hacer una primera distincin
entre aquellos sistemas donde slo hay un procesador, sistemas
monoprocesador, y aquellos en los que hay ms de un procesador, sistemas
multiprocesador. En ambos sistemas es posible tener concurrencia.

1.4.1 Sistemas monoprocesador


Incluso en un sistema con un solo procesador podemos tener una ejecucin
concurrente de procesos. Evidentemente todos los procesos no pueden estar
ejecutndose al mismo tiempo sobre el procesador, slo uno de ellos podr estar
hacindolo, pero la sensacin que le da al usuario o grupo de usuarios es la de
estar ejecutndose al mismo tiempo. Esto es debido a que el Sistema Operativo
(SO) va alternando el tiempo de procesador entre los distintos procesos. De esta
forma, cuando un proceso que ocupa el procesador en un momento determinado
necesita hacer una operacin de entrada/salida, puede abandonar el procesador
para que otro proceso pueda ocuparlo y aprovechar ciclos de procesador. En la
Figura 3 puede verse cmo el tiempo de procesador es repartido entre tres
procesos. Esta forma de gestionar los procesos en un sistema monoprocesador
recibe el nombre de multiprogramacin y es otro de los beneficios de la
programacin concurrente: un mayor aprovechamiento del procesador.
Esto es lo que ocurre en los SO que estamos acostumbrados a manejar con los
ordenadores de sobremesa tales como Windows o Linux.

P1
P2
P3

Figura 3 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 1.3.2.

M.E Carmen Cern G Programacin Concurrente BUAP 6


En un sistema monoprocesador todos los procesos comparten la misma
memoria. La forma de sincronizar y comunicar procesos ser pues mediante el
uso de variables compartidas. Tal y como muestra la Figura 4 cuando un
proceso A quiere comunicar algo a un proceso B lo deja en una variable conocida
y compartida por ambos procesos de tal forma que el proceso B lo pueda leer.

Variable
compartida MEMORIA comn a
todos los procesos

escribe lee

proceso proceso proceso


A B C

SISTEMA OPERATIVO

procesador

Figura 4 Sistema monoprocesador con variables compartidas.

1.4.2 Sistemas multiprocesador


Un sistema multiprocesador es aquel en el que existe ms de un procesador. Esto
permite que exista un paralelismo real entre los procesos ya que idealmente cada
procesador podra ejecutar un proceso. Si tuvisemos un sistema con tres
procesadores en vez de tener la Figura 3 el resultado podra ser el de la Figura 5
en el que realmente los tres procesos se ejecutan de forma paralela.
P1
P2
P3

Figura 5 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.

Dentro de los sistemas multiprocesadores se puede hacer una pequea


clasificacin:

M.E Carmen Cern G Programacin Concurrente BUAP 7


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 (Figura 6).

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
Variable B
compartida MEMORIA comn a
todos los procesos

paso de mensaje
escribe lee
procesador

proceso proceso proceso


A B C
nodo
A nodo
C

SISTEMA OPERATIVO

procesador
procesador
procesador

procesador procesador procesador


Figura 7 Sistema distribuido.
Figura 6 Sistema multiprocesador con
memoria compartida.

Suele denominarse multiproceso a la gestin de varios procesos dentro de un


sistema multiprocesador donde cada procesador puede acceder a una memoria
comn y procesamiento distribuido a la gestin de varios procesos en
procesadores separados, cada uno con su memoria local.
Mientras que en los sistemas de multiproceso el esquema de la Figura 4 se
puede seguir manteniendo tal y como se muestra en la Figura 6, en el
procesamiento distribuido este esquema ya no es vlido. En un sistema distribuido
la forma natural de comunicar y sincronizar procesos es mediante el uso de paso
de mensaje tal y como se aprecia en la Figura 7. 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

M.E Carmen Cern G Programacin Concurrente BUAP 8


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

En este libro 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.

1.5 Especificacin de 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.

1.5.1 Qu se puede ejecutar concurrentemente?


Obviamente, no todas las partes de un programa pueden ejecutarse de forma
concurrente. Consideremos el siguiente fragmento de programa:

x:=x+1;
y:=x+2;

Est claro que la primera sentencia se tiene que ejecutar antes que la segunda.
Sin embargo consideremos ahora:

x:=1;
y:=2;
z:=3;

Queda claro que el orden en que se ejecuten no interviene en el resultado final.


Si dispusisemos de tres procesadores podramos ejecutar cada una de las lneas
en uno de ellos incrementando la velocidad del sistema.
En el caso anterior, el sentido comn es el que nos ha hecho ver qu se poda y
qu no se poda ejecutar concurrentemente. Sin embargo, A. J. Bernstein

M.E Carmen Cern G Programacin Concurrente BUAP 9


[Bernstein, 1966] defini unas condiciones para determinar si dos conjuntos de
instrucciones Si y Sj se pueden ejecutar concurrentemente.

Condiciones de Bernstein
Para poder determinar si dos conjuntos de instrucciones se pueden ejecutar de
forma concurrente, se definen en primer lugar los siguientes conjuntos:
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) = {b1, b2, ... , bm}, como el conjunto de escritura del conjunto de
instrucciones Sk y que est formado por todas las variables cuyos valores
son actualizados (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:

1. L(Si) E(Sj) =
2. E(Si) L(Sj) =
3. E(Si) E(Sj) =

Como ejemplo supongamos que tenemos:

S1 a := x+y;
S2 b := z-1;
S3 c := a-b;
S4 w := c+1;

Utilizando las condiciones de Bernstein veremos qu sentencias pueden


ejecutarse de forma concurrente y cules no. Para ello, en primer lugar calculamos
los conjuntos de lectura y escritura:

L (S1) = {x, y}E (S1) = {a}


L (S2) = {z} E (S2) = {b}
L (S3) = {a, b} E (S3) = {c}
L (S4) = {c} E (S4) = {w}

Ahora aplicamos las condiciones de Bernstein a cada par de sentencias:

Entre S1 y S2: L(S1) E(S3) =


L(S1) E(S2) = E(S1) L(S3) = a
E(S1) L(S2) = E(S1) E(S3) =
E(S1) E(S2) =

Entre S1 y S4:
Entre S1 y S3:

M.E Carmen Cern G Programacin Concurrente BUAP 10


L(S1) E(S4) = L(S2) E(S4) =
E(S1) L(S4) = E(S2) L(S4) =
E(S1) E(S4) = E(S2) E(S4) =

Entre S2 y S3: Entre S3 y S4:


L(S2) E(S3) = L(S3) E(S4) =
E(S2) L(S3) = b E(S3) L(S4) = c
E(S2) E(S3) = E(S3) E(S4) =

Entre S2 y S4:
De todo esto se deduce la siguiente tabla en la que puede verse qu pares de
sentencias pueden ejecutarse de forma concurrente:

S1 S2 S3 S4
S1 -- S No S
S2 -- -- No S
S3 -- -- -- No
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.

1.5.2 Cmo especificar la ejecucin concurrente


Veremos dos posibles formas de especificar la ejecucin concurrente de
instrucciones: una basada en una notacin grfica y otra basada en lo que suelen
utilizar diversos lenguajes de programacin, el par cobegin/coend.

Grafos de precedencia
Se trata de una notacin grfica. Es un grafo dirigido acclico. Cada nodo
representar una parte (conjunto de instrucciones) de nuestro sistema. Una flecha
desde A hasta B representa que B slo puede ejecutarse cuando A haya
finalizado. Si aparecen dos nodos en paralelo querr decir que se pueden ejecutar
concurrentemente.
Para el ejemplo anterior el grafo de precedencia sera el de la Figura 8.

M.E Carmen Cern G Programacin Concurrente BUAP 11


S1 S2

S3

S4

Figura 8 Grafo de precedencia.

Sentencias COBEGIN-COEND
Todas aquellas acciones que puedan ejecutarse concurrentemente las
introducimos dentro del par cobegin/coend. El ejemplo anterior quedara de la
siguiente forma:

begin
cobegin
a:=x+y;
b:=z+1;
coend;
c:=a-b;
w:=c+1;
end.

Las instrucciones dentro del par cobegin/coend pueden ejecutarse en cualquier


orden, mientras que el resto se ejecuta de manera secuencial.

1.6 Caractersticas de los sistemas concurrentes


La ejecucin de sistemas concurrentes tiene algunas caractersticas que los
diferencian claramente de los sistemas secuenciales. Destacamos dos:

1.6.1 Orden de ejecucin de las instrucciones


En los programas secuenciales hay un orden total en la ejecucin de las lneas
de cdigo. Ante un conjunto de datos de entrada se sabe siempre por dnde va a
ir el programa (su flujo de ejecucin). En la Figura 9, por muchas veces que se
ejecute el programa, el hilo de ejecucin siempre tendr el mismo recorrido, es
decir, las instrucciones siempre se ejecutarn en el mismo orden.

M.E Carmen Cern G Programacin Concurrente BUAP 12


hilo de ejecucin

i1 i1 i1
i2 i2 i2
programa
i3 i3 i3
i4 i4 i4
i6 i6 i6
i5 i5 i5
i7 i7 i7

Figura 9 Orden total. Figura 10 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 10, 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 11 podemos observar el grafo de precedencia y el cdigo con el
par cobegin/coend para el caso de la Figura 10.

begin
cobegin
i1 i2 i3 i4 i5 i6 i7 i1; i2; i3; i4; i5; i6; i7;
coned;
end.

Figura 11 Orden parcial: grafo de precedencia y cdigo.

1.6.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.
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;

M.E Carmen Cern G Programacin Concurrente BUAP 13


process P1;
var i: integer;
begin
for i:=1 to 5 do x:=x+1; begin
end; x:=0;
cobegin
process P2; P1;
var j: integer; P2;
begin coend;
for j:=1 to 5 do x:=x+1 end.
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.

1.7 Problemas inherentes a la programacin concurrente


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.

1.7.1 Exclusin mutua


Este problema es el que se nos da en el ejemplo anterior de los bucles. Antes de
pasar a explicar el problema hay que tener en cuenta que lo que realmente se
ejecuta concurrentemente son las lneas de cdigo generadas por el compilador.
En nuestro caso, supongamos que una instruccin como x:=x+1 da lugar a tres
instrucciones de un lenguaje ensamblador cualquiera, que es lo que realmente va
a ejecutar el procesador. Tendramos los siguientes pasos:
1. Cargar desde memoria el valor de x en un registro (LOAD X R1).
2. Incrementar el valor del registro (ADD R1 1).
3. Almacenar el contenido del registro en la posicin de memoria de x
(STORE R1 X).
As pues, lo que realmente se va a ejecutar de forma concurrente dentro de
cada bucle es:

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

M.E Carmen Cern G Programacin Concurrente BUAP 14


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 12 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 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.

x 0 0 0 0 1 1 1
P1 1 2 3
P2 1 2 3
Tiempo

Figura 12 Traza de una posible ejecucin concurrente para P1 y P2.

En cualquier caso, el hecho de que P1 y P2 no puedan ejecutarse


concurrentemente viene determinado por las condiciones de Bernstein pues sus
conjuntos de escritura no son disjuntos. El problema estriba en que dos procesos
distintos estn accediendo al mismo tiempo a una variable compartida entre los
dos para actualizarla. Nos hubiese interesado que las tres lneas de cada proceso
se hubiesen ejecutado en un solo paso, sin ningn tipo de intercalado con las
otras lneas del otro proceso. A la porcin de cdigo que queremos que se ejecute
de forma indivisible se le denomina seccin crtica. Nos interesa asegurarnos que
las secciones crticas se ejecuten en exclusin mutua, es decir, slo uno de los
procesos debe estar en la seccin crtica en un instante dado. En la Figura 13
puede verse cmo cuando los dos procesos llegan a la seccin crtica slo uno de
ellos podr entrar, teniendo que esperar el otro. En la Figura 14 puede verse que
una vez que un proceso ha salido de la seccin crtica, el otro proceso puede
entrar y de esta forma seguir ejecutndose los dos de manera concurrente.
P1 P2 Figura 13 Seccin crtica (1).

Seccin crtica
x:=x+1

M.E Carmen Cern G Programacin Concurrente BUAP 15


Figura 14 Seccin crtica (2).
P1 P2

Seccin crtica
x:=x+1

La programacin concurrente deber ofrecernos mecanismos para especificar


qu partes del cdigo han de ejecutarse en exclusin mutua con otras partes.

1.7.2 Condicin de sincronizacin


Para ilustrar el problema de la condicin de sincronizacin supongamos ahora un
sistema en el que existen tres procesos (Figura 15) cuyo comportamiento es el
siguiente:
lector, que va almacenando en un buffer las imgenes capturadas desde
una cmara
gestor, que va recogiendo las imgenes desde el buffer, las trata y las va
colocando en una cola de impresin
impresor, que va imprimiendo las imgenes colocadas en la cola de
impresin

cmara impresora

LECTOR GESTOR IMPRESOR

buffer cola de impresin

Figura 15 Sistema compuesto por los procesos lector, gestor e impresor.

Supongamos que los tres procesos se ejecutan de manera concurrente en un


bucle infinito tal y como muestra el siguiente pseudocdigo:

process lector; process gestor; process impresor;


begin begin begin
repeat repeat repeat
captura imagen; coge imagen de buffer; coge imagen de cola;
almacena en buffer; trata imagen; imprime imagen;
forever almacena imagen en cola; forever
end; forever end;
end;

M.E Carmen Cern G Programacin Concurrente BUAP 16


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 (p. ej. que el buffer deje de estar vaco), pero tambin
que permita desbloquearlos cuando ese evento haya ocurrido.

A la solucin de estos dos problemas usando diferentes tcnicas es a lo que


dedicaremos gran parte del libro.

1.8 Correccin de programas concurrentes


El orden parcial e indeterminismo en la ejecucin de las instrucciones hace que
la correccin de un programa concurrente sea ms difcil de conseguir que la
de un programa secuencial. Para que un programa concurrente sea correcto,
adems de cumplir las especificaciones funcionales que deba cumplir, debe
satisfacer una serie de propiedades inherentes a la concurrencia. Podemos
agrupar esas propiedades en:
Propiedades de seguridad: son aquellas que aseguran que nada
malo va a pasar durante la ejecucin del programa.
Propiedades de viveza: son aquellas que aseguran que algo
bueno pasar eventualmente durante la ejecucin del programa.

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 16). 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 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.

M.E Carmen Cern G Programacin Concurrente BUAP 17


el 2

Figura 16 Juego del pauelo.

Propiedades de seguridad
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.

Problemas de vivacidad
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

M.E Carmen Cern G Programacin Concurrente BUAP 18


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.

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.

Ejercicios resueltos

M.E Carmen Cern G Programacin Concurrente BUAP 19


1. Construir un programa concurrente que se corresponda con el grafo de
precedencia de la siguiente figura utilizando el par cobegin/coend

S1

S2 S3

S4

S5 S6

S7

Solucin:
S1;
cobegin
S3;
begin
S2;
S4;
cobegin
S5;
S6;
coend
end;
coend;
S7;

2. Dado el siguiente trozo de cdigo obtener su grafo de precedencia


correspondiente.
s0;
cobegin
s1;
begin
s2;
cobegin
s3;s4
coend;
s5
end;
s6
coend;
s7

M.E Carmen Cern G Programacin Concurrente BUAP 20


Solucin:
S0

S2

S1 S3 S4 S6

S5

S7

3. Construir un programa concurrente que explote al mximo la concurrencia


para copiar un fichero f en un fichero g utilizando el par cobegin/coend.

Solucin:
var f, g: file of T;
r s: T;
count: integer;
begin
abrirLectura (f);
abrirEscritura (g);
leer (f,s);
while not finFichero (f) do begin
s:=r;
cobegin
escribir (g,s);
leer (f,r);
coend
escribir (g,r);
end;

Ejercicios propuestos
Cuestiones breves
1. Cul es la ventaja de la concurrencia en los sistemas monoprocesador?
2. Cules son las diferencias entre programacin concurrente, paralela y
distribuida?
3. Cules son las diferencias entre multiprogramacin, multiproceso y
procesamiento distribuido?
4. Cules son los dos problemas principales inherentes a la programacin
concurrente?
5. Qu es una seccin crtica?
6. Cules son las caractersticas de un programa concurrente?
7. Qu se entiende por un programa concurrente correcto?

M.E Carmen Cern G Programacin Concurrente BUAP 21


Problemas
1. 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;

2. Construir dos programas concurrentes que se correspondan con los de la


siguiente figura utilizando el par cobegin/coend.

S1 S1

S2 S5 S2 S3

S3 S4
S4

S5 S6

S7
S6

M.E Carmen Cern G Programacin Concurrente BUAP 22