1 of 13

Lenguajes de Programación I

Ej. 4 – Parcial 2024

2 of 13

Se tiene un lenguaje con concurrencia bajo la forma de hilos de ejecución.

  1. Para cada una de las 3 situaciones A, B y C ilustradas en los siguientes diagramas de memoria (se muestran los nombres de variables, dirección y valores sucesivos separados por punto y coma), escribir un programa en pseudocódigo o en una sintaxis tipo C++ que se corresponda con la ejecución, indicando claramente las variables del programa y su tipo de almacenamiento. La función f recibe un parámetro id por copia valor.
  2. Indicar en cuál/es de las 3 situaciones es necesario un semáforo para evitar accesos simultáneos a variables.
  3. Si se reemplaza la variable estática por otra que sea un puntero a una variable dinámica anónima y se modifica el programa para que sea esta variable la que se modifique, indicar si el programa correspondiente se comporta igual o no.
  4. Realizar un diagrama de memoria en donde sea el parámetro id el que se decrementa. ¿Qué sucede con la ejecución?
  5. Responder el inciso d) si el parámetro id se pasa por referencia, el parámetro real es la variable estática y el parámetro id es el que se decrementa.

Aclaraciones: El diagrama 3 provoca una recursión infinita.

3 of 13

  • Para cada una de las 3 situaciones A, B y C ilustradas en los siguientes diagramas de memoria (se muestran los nombres de variables, dirección y valores sucesivos separados por punto y coma), escribir un programa en pseudocódigo o en una sintaxis tipo C++ que se corresponda con la ejecución, indicando claramente las variables del programa y su tipo de almacenamiento. La función f recibe un parámetro id por copia valor.

Se observan 3 pilas separadas

Existen 3 hilos

Uno es el main

El main crea 2 hilos a partir de la función f

func main() {

creahilo(f, 100)

creahilo(f, 200)

}

func f(id) {

}

Esto lo dice el enunciado

4 of 13

  • Para cada una de las 3 situaciones A, B y C ilustradas en los siguientes diagramas de memoria (se muestran los nombres de variables, dirección y valores sucesivos separados por punto y coma), escribir un programa en pseudocódigo o en una sintaxis tipo C++ que se corresponda con la ejecución, indicando claramente las variables del programa y su tipo de almacenamiento. La función f recibe un parámetro id por copia valor.

func main() {

creahilo(f, 100)

creahilo(f, 200)

}

func f(id) {

}

static z = 2

  • Todos los diagramas tienen una variable z estática
  • Las pilas de f tienen una variable y static thread
  • Los registros de activación de f tienen una variable local x

static_thread y = 2

x = 2

5 of 13

  • Para cada una de las 3 situaciones A, B y C ilustradas en los siguientes diagramas de memoria (se muestran los nombres de variables, dirección y valores sucesivos separados por punto y coma), escribir un programa en pseudocódigo o en una sintaxis tipo C++ que se corresponda con la ejecución, indicando claramente las variables del programa y su tipo de almacenamiento. La función f recibe un parámetro id por copia valor.

func main() {

creahilo(f, 100)

creahilo(f, 200)

}

func f(id) {

}

static z = 2

static_thread y = 2

x = 2

¿Qué se deduce del diagrama A?

f(id+1)

  • Se decrementa “y” hasta llegar a 0

y - -

if y > 0

  • Cada f se llama recursivamente con id+1

6 of 13

  • Para cada una de las 3 situaciones A, B y C ilustradas en los siguientes diagramas de memoria (se muestran los nombres de variables, dirección y valores sucesivos separados por punto y coma), escribir un programa en pseudocódigo o en una sintaxis tipo C++ que se corresponda con la ejecución, indicando claramente las variables del programa y su tipo de almacenamiento. La función f recibe un parámetro id por copia valor.

func main() {

creahilo(f, 100)

creahilo(f, 200)

}

func f(id) {

}

static z = 2

static_thread y = 2

x = 2

¿Qué se deduce del diagrama B?

f(id+1)

  • Se decrementa “z” hasta llegar a 0

z - -

if z > 0

  • Cada f se llama recursivamente con id+1

7 of 13

  • Para cada una de las 3 situaciones A, B y C ilustradas en los siguientes diagramas de memoria (se muestran los nombres de variables, dirección y valores sucesivos separados por punto y coma), escribir un programa en pseudocódigo o en una sintaxis tipo C++ que se corresponda con la ejecución, indicando claramente las variables del programa y su tipo de almacenamiento. La función f recibe un parámetro id por copia valor.

func main() {

creahilo(f, 100)

creahilo(f, 200)

}

func f(id) {

}

static z = 2

static_thread y = 2

x = 2

¿Qué se deduce del diagrama C?

f(id+1)

  • Se decrementa “x” hasta llegar a 0

x - -

if x > 0

  • Cada f se llama recursivamente con id+1

¿Por qué el programa tiene recursión infinita?

8 of 13

void f(int id){

int x=2;

static thread_local int y=2;

static int z = 2;

printf("id : %d, x: %d, y: %d, z: %d,\n",id,x,y,x);

printf("id : %d, &x: %d, &y: %d, &z: %d\n",id,&x,&y,&z);

VAR--;

if (VAR>0)

f(id+1);

}

int main (int argc, char *argv[]){

thread th1(f,100);

thread th2(f,200);

th1.join();

th2.join();

return 0;

}

Código en C++

func main() {

creahilo(f, 100)

creahilo(f, 200)

}

func f(id) {

}

static z = 2

static_thread y = 2

x = 2

f(id+1)

x - -

if x > 0

9 of 13

¿En cuál situación se comparte simultáneamente una variable?

func main() {

creahilo(f, 100)

creahilo(f, 200)

}

func f(id) {

}

static z = 2

static_thread y = 2

x = 2

f(id+1)

z - -

if z > 0

b) Indicar en cuál/es de las 3 situaciones es necesario un semáforo para evitar accesos simultáneos a variables.

En la situación B

Semaforo arriba

Semaforo abajo

10 of 13

c) Si se reemplaza la variable estática por otra que sea un puntero a una variable dinámica anónima y se modifica el programa para que sea esta variable la que se modifique, indicar si el programa correspondiente se comporta igual o no.

func main() {

creahilo(f, 100)

creahilo(f, 200)

}

func f(id) {

}

static z = new int

static_thread y = 2

x = 2

f(id+1)

*z - -

if *z > 0

El programa se comporta igual que en el caso que se decremente z, ya que de cualquier manera los hilos van a compartir el valor que se encuentra en el heap

11 of 13

func main() {

creahilo(f, 100)

creahilo(f, 200)

}

func f(id) {

}

static z = 2

static_thread y = 2

x = 2

f(id+1)

id - -

if id > 0

d) Realizar un diagrama de memoria en donde sea el parámetro id el que se decrementa. ¿Qué sucede con la ejecución?

z $10: 2

V.E.

main

id $220: 100;99

x $210: 2

y $200: 2

id $240: 100;99

x $230: 2

static

thread

f

f

id $520: 200;199

x $510: 2

y $500: 2

static

thread

f

id $260: 100;99

x $250: 2

f

id $540: 200;199

x $530: 2

f

Se produce una recursión infinita, ya que id se inicializa en cada llamado a f

12 of 13

e) Responder el inciso d) si el parámetro id se pasa por referencia, el parámetro real es la variable estática y el parámetro id es el que se decrementa.

func main() {

creahilo(f, 100)

creahilo(f, 200)

}

func f(id) {

}

static z = new int

static_thread y = 2

x = 2

f(ref z)

id - -

if id > 0

z $10: 2; 1; 0

V.E.

main

x $210: 2

y $200: 2

x $230: 2

static

thread

f

f

x $510: 2

y $500: 2

static

thread

f

x $250: 2

f

x $530: 2

f

Es la misma situación que cuando se modifica z

13 of 13

Errores frecuentes

  • Se colocaron llamadas a f explícitas según la cantidad de registros de activación que había, en lugar de llamados recursivos según una condición.
  • Se implementó una iteración en lugar de un llamado recursivo a f
  • Se crearon hilos anónimos en lugar de utilizar f
  • Se pasaron como parámetros las variables x, y, z
  • Se ubicaron las variables x, y, z como globales