Semana 13: Unidad 4

Trayecto de acciones, tiempos y formas de trabajo

Actividad 9

  • Fecha: septiembre 28 de 2020 - 4:00 p.m
  • Descripción: discutir grupalmente las técnicas de comunicación entre procesos y dudas sobre el reto.
  • Recursos: ingresa a Teams
  • Duración de la actividad: 1 hora 40 minutos
  • Forma de trabajo: individual con solución de dudas en tiempo real

Esta semana veremos otra de las estrategias de comunicación entre procesos: memoria compartida.

Material

En este enlace se encuentra el material para esta semana.

Ejemplo 1

El siguiente ejemplo muestra como dos procesos pueden comunicarse utilizando memoria compartida.

El primer proceso crea la memoria compartida y escribe información. El segundo proceso la lee y destruye la memoria compartida.

Proceso 1:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/mman.h>
 #include <sys/stat.h>        /* For mode constants */
 #include <fcntl.h>           /* For O_* constants */
 #include <string.h>
 #include <unistd.h>
 #include <sys/types.h>


 #define SH_SIZE 16

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

     int shm_fd = shm_open("shm0", O_CREAT | O_RDWR, 0600);
     if (shm_fd < 0) {
         perror("shm memory error: ");
         exit(EXIT_FAILURE);
     }
     fprintf(stdout, "Shared memory is created with fd: %d\n", shm_fd);

     if (ftruncate(shm_fd, SH_SIZE * sizeof(char)) < 0) {
         perror("Truncation failed: ");
         exit(EXIT_FAILURE);
     }

     fprintf(stdout, "The memory region is truncated.\n");

     void* map = mmap(NULL, SH_SIZE, PROT_WRITE, MAP_SHARED, shm_fd, 0);

     if (map == MAP_FAILED) {
         perror("Mapping failed: ");
         exit(EXIT_FAILURE);
     }

     char* ptr = (char*)map;
     ptr[0] = 'A';
     ptr[1] = 'B';
     ptr[2] = 'C';
     ptr[3] = '\n';
     ptr[4] = '\0';

     fprintf(stdout, "Data is written to the shared memory.\n");

     if (munmap(ptr, SH_SIZE) < 0) {
         perror("Unmapping failed: ");
         exit(EXIT_FAILURE);
     }


     if (close(shm_fd) < 0) {
         perror("Closing shm failed: ");
         exit(EXIT_FAILURE);
     }

     exit(EXIT_SUCCESS);
 }

Proceso 2:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/mman.h>
 #include <sys/stat.h>        /* For mode constants */
 #include <fcntl.h>           /* For O_* constants */
 #include <string.h>
 #include <unistd.h>
 #include <sys/types.h>

 #define SH_SIZE 16

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

     int shm_fd = shm_open("shm0", O_RDONLY, 0600);
     if (shm_fd < 0) {
         perror("shm memory error: ");
         exit(EXIT_FAILURE);
     }
     fprintf(stdout, "Shared memory is created with fd: %d\n", shm_fd);

     void* map = mmap(NULL, SH_SIZE, PROT_READ, MAP_SHARED, shm_fd, 0);

     if (map == MAP_FAILED) {
         perror("Mapping failed: ");
         exit(EXIT_FAILURE);
     }

     char* ptr = (char*)map;
     fprintf(stdout, "The contents of shared memory object: %s\n", ptr);


     if (munmap(ptr, SH_SIZE) < 0) {
         perror("Unmapping failed: ");
         exit(EXIT_FAILURE);
     }


     if (close(shm_fd) < 0) {
         perror("Closing shm failed: ");
         exit(EXIT_FAILURE);
     }

     if (shm_unlink("shm0") < 0) {
         perror("Unlink failed: ");
         exit(EXIT_FAILURE);
     }

     exit(EXIT_SUCCESS);
 }

Para ejecutar los programas sigue estos pasos:

1
2
 gcc -Wall p1.c -o p1 -lrt
 ./p1

El proceso 1 terminará pero abra dejado la zona de memoria compartida lista y con datos. Para verificarlo:

1
2
 ls /dev/shm
 cat /dev/shm/shm0

Ahora compile y ejecute el proceso 2.

1
2
 gcc -Wall p2.c -o p2 -lrt
 ./p2

Ejemplo 2

El siguiente ejemplo muestra la necesidad de incluir mecanismos de sincronización para evitar condiciones de carrera.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
 #include <stdio.h>
 #include <stdint.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <fcntl.h>
 #include <errno.h>
 #include <string.h>
 #include <sys/mman.h>
 #include <sys/wait.h>

 #define SH_SIZE 4

 int shared_fd = -1;
 int32_t* counter = NULL;


 void init_shared_resource() {
 shared_fd = shm_open("shm0", O_CREAT | O_RDWR, 0600);
 if (shared_fd < 0) {
     perror("Failed to create shared memory: ");
     exit(EXIT_FAILURE);
 }
 fprintf(stdout, "Shared memory is created with fd: %d\n", shared_fd);
 }

 void shutdown_shared_resource() {
 if (shm_unlink("shm0") < 0) {
     perror("Unlinking shared memory failed: ");
     exit(EXIT_FAILURE);
 }
 }

 void inc_counter() {
 usleep(1);
 int32_t temp = *counter;
 usleep(1);
 temp++;
 usleep(1);
 *counter = temp;
 usleep(1);
 }


 int main(int argc, char** argv) {
 init_shared_resource();
 if (ftruncate(shared_fd, SH_SIZE * sizeof(char)) < 0) {
     perror("Truncation failed: ");
     exit(EXIT_FAILURE);
 }
 fprintf(stdout, "The memory region is truncated.\n");
 void* map = mmap(0, SH_SIZE, PROT_WRITE, MAP_SHARED, shared_fd, 0);

 if (map == MAP_FAILED) {
     perror("Mapping failed: ");
     exit(EXIT_FAILURE);
 }

 counter = (int32_t*)map;
 *counter = 0;

 pid_t pid = fork();
 if (pid) { // The parent process
     inc_counter();
     fprintf(stdout, "The parent process sees the counter as %d.\n", *counter);
     int status = -1;
     wait(&status);
     fprintf(stdout, "The child process finished with status %d.\n", status);
 } else { // The child process
     inc_counter();
     fprintf(stdout, "The child process sees the counter as %d.\n", *counter);
 }


 if (munmap(counter, SH_SIZE) < 0) {
     perror("Unmapping failed: ");
     exit(EXIT_FAILURE);
 }

 if (close(shared_fd) < 0) {
     perror("Closing shared memory fd failed: ");
     exit(EXIT_FAILURE);
 }

 if (pid) {
     shutdown_shared_resource();
 }

 exit(EXIT_SUCCESS);
 }

Compila el código y luego ejecútela varias veces hasta generar la condición de carrera.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
 gcc -Wall p3.c -o p3 -lrt

 juanfranco@pop-os:~/tmp4$ ./p3
 Shared memory is created with fd: 3
 The memory region is truncated.
 The parent process sees the counter as 1.
 The child process sees the counter as 2.
 The child process finished with status 0.

 juanfranco@pop-os:~/tmp4$ ./p3
 Shared memory is created with fd: 3
 The memory region is truncated.
 The parent process sees the counter as 1.
 The child process sees the counter as 1.
 The child process finished with status 0.

El resultado esperado es que siempre el contador quede en 2, pero a veces queda en uno.

Ejercicio 3

Este ejercicio muestra cómo corregir el error del ejercicio 2 debido a los problemas de sincronización

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
 #include <stdio.h>
 #include <stdint.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <fcntl.h>
 #include <errno.h>
 #include <string.h>
 #include <sys/mman.h>
 #include <sys/wait.h>
 #include <semaphore.h>

 #define SH_SIZE 4

 int shared_fd = -1;
 int32_t* counter = NULL;
 sem_t* semaphore = NULL;

 void init_control_mechanism() {
     semaphore = sem_open("sem0", O_CREAT, 0600, 1);
     if (semaphore == SEM_FAILED) {
         perror("Opening the semaphore failed: ");
         exit(EXIT_FAILURE);
     }
 }

 void shutdown_control_mechanism() {
     if (sem_close(semaphore) < 0) {
         perror("Closing the semaphore failed: ");
         exit(EXIT_FAILURE);
     }

     if (sem_unlink("sem0") < 0) {
         perror("Unlinking failed: ");
         exit(EXIT_FAILURE);
     }
 }

 void init_shared_resource() {
     shared_fd = shm_open("shm0", O_CREAT | O_RDWR, 0600);
     if (shared_fd < 0) {
         perror("Failed to create shared memory: ");
         exit(EXIT_FAILURE);
     }
     fprintf(stdout, "Shared memory is created with fd: %d\n", shared_fd);
 }

 void shutdown_shared_resource() {
     if (shm_unlink("/shm0") < 0) {
         perror("Unlinking shared memory failed: ");
         exit(EXIT_FAILURE);
     }
 }

 void inc_counter() {
     usleep(1);
     sem_wait(semaphore);
     int32_t temp = *counter;
     usleep(1);
     temp++;
     usleep(1);
     *counter = temp;
     sem_post(semaphore);
     usleep(1);
 }


 int main(int argc, char** argv) {
     init_shared_resource();
     init_control_mechanism();

     if (ftruncate(shared_fd, SH_SIZE * sizeof(char)) < 0) {
         perror("Truncation failed: ");
         exit(EXIT_FAILURE);
     }
     fprintf(stdout, "The memory region is truncated.\n");
     void* map = mmap(0, SH_SIZE, PROT_WRITE, MAP_SHARED, shared_fd, 0);

     if (map == MAP_FAILED) {
         perror("Mapping failed: ");
         exit(EXIT_FAILURE);
     }

     counter = (int32_t*)map;
     *counter = 0;

     pid_t pid = fork();
     if (pid) { // The parent process
         inc_counter();
         fprintf(stdout, "The parent process sees the counter as %d.\n", *counter);
         int status = -1;
         wait(&status);
         fprintf(stdout, "The child process finished with status %d.\n", status);
     } else { // The child process
         inc_counter();
         fprintf(stdout, "The child process sees the counter as %d.\n", *counter);
         if (sem_close(semaphore) < 0) {
             perror("Closing the semaphore failed: ");
         }
     }


     if (munmap(counter, SH_SIZE) < 0) {
         perror("Unmapping failed: ");
         exit(EXIT_FAILURE);
     }

     if (close(shared_fd) < 0) {
         perror("Closing shared memory fd failed: ");
         exit(EXIT_FAILURE);
     }

     if (pid) {
         shutdown_shared_resource();
         shutdown_control_mechanism();
     }

     exit(EXIT_SUCCESS);
 }

Ejercicio 4: RETO

Crear un chat entre dos procesos utilizando memoria compartida, hilos y semáforos. Cada proceso deberá esperar por la entrada de su usuario y al mismo tiempo mostrar los mensajes enviados por el otro usuario (es por ello que se requiere tener dos hilos por proceso).

El intercambio de mensajes se debe realizar utilizando memoria compartida y semáforos para la sincronización.

Actividad 10

  • Fecha: septiembre 28 a octubre 2 de 2020
  • Descripción: solución del reto
  • Recursos: material teórico de la unidad
  • Duración de la actividad: 5 horas
  • Forma de trabajo: trabajo individual en la solución del reto

Actividad 11

  • Fecha: octubre 2 de 2020 - 4:00 p.m
  • Descripción: sustentación
  • Recursos: ingresa a Teams
  • Duración de la actividad: 1 hora 40 minutos
  • Forma de trabajo: sustentación individual con cada estudiante.