Documentos de Académico
Documentos de Profesional
Documentos de Cultura
en Computación Sistemas Operativos
Sistemas Operativos
Problemas de comunicación y sincronización (Lectores-Escritores).
En el presente documento se explica como crear una aplicación gráfica que utiliza una tubería sin
nombre como mecanismo de sincronización para simular el problema de los Lectores-Escritores.
Primero crearemos la ventana principal utilizando la aplicación Glade-2 mediante los siguientes pasos:
1.- Generamos un Nuevo Proyecto GTK +
2.- De la Paleta de Widgets seleccionamos Window
3.- En la ventana de propiedades del widget window configuramos lo siguiente:
a) Nombre: window
b) Título: Lectores-Escritores
c) Ancho y largo de 250
d) Añadimos la señal destroy
4.- Adicionamos y configuramos widgets de la siguiente forma:
a) Adicionamos una caja vertical con dos renglones a window
b) En el primer renglón adicionamos una barra de herramientas con dos botones
c) El primer botón será para el cuadro Acerca de (usar botón de stock y añadir la señal clicked)
d) El segundo botón será para salir (usar botón de stock y añadir la señal clicked)
e) En el segundo renglón adicionamos una área de dibujo (Drawing Area), cambiar el nombre a
drawingarea y añadir las señales de configure_event y expose_event a este widget
5.- Guardar como LectoresEscritores y construir
6.- Entramos a la terminal y nos cambiamos a la ruta del proyecto
cd Projects/LectoresEscritores/
7.- Ejecutamos la autogeneración y compilamos
./autogen.sh
make
8.- Nos cambiamos al directorio de los fuentes y editamos el archivo callbacks.c
cd src/
gedit callbacks.c
9.- El código de la retrollamada on_window_destroy deberá quedar como sigue:
void
on_window_destroy (GtkObject *object,
gpointer user_data)
{
gtk_main_quit();
}
Esto hará que se salga del bucle de procesamiento de las señales y se termine la aplicación.
M. en C. J. Jesús Arellano Pimentel Abril 2011
Unistmo Ing. en Computación Sistemas Operativos
pixmap = gdk_pixmap_new(widget->window,
widget->allocation.width,
widget->allocation.height,
-1);
trazar(widget);
return TRUE;
}
gboolean
on_drawingarea_expose_event (GtkWidget *widget,
GdkEventExpose *event,
gpointer user_data)
{
gdk_draw_pixmap(widget->window,
widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
pixmap,
event->area.x, event->area.y,
event->area.x, event->area.y,
event->area.width, event->area.height);
return FALSE;
}
Observe que en código anterior se utiliza una variable de nombre pixmap y un procedimiento llamado
trazar, la creación de estos dos elementos se detallan en los siguientes pasos.
12.- Declaramos la variable global pixmap después de la inclusión de librerías
GdkDrawable * pixmap = NULL;
Esta variable es prácticamente el lienzo sobre el cual vamos a dibujar.
13.- Implementamos, abajo de la declaración de la variable anterior, el procedimiento trazar
int trazar(GtkWidget * widget)
{
GdkRectangle update_rect;
GtkWidget *where_to_draw = lookup_widget(widget,"drawingarea");
GdkFont *font = NULL;
M. en C. J. Jesús Arellano Pimentel Abril 2011
Unistmo Ing. en Computación Sistemas Operativos
if(font == NULL)
if((font = gdk_font_load("fixed"))==NULL)
return FALSE;
gdk_draw_rectangle(pixmap, widget->style->white_gc,
TRUE,
0, 0,
where_to_draw->allocation.width,
where_to_draw->allocation.height);
update_rect.x = 0;
update_rect.y = 0;
update_rect.width = where_to_draw->allocation.width;
update_rect.height = where_to_draw->allocation.height;
gtk_widget_draw(where_to_draw, &update_rect);
return TRUE;
}
Este procedimiento solo “limpia” el área de dibujo con un rectángulo relleno de color blanco toda el
área cliente de la ventana.
14.- En este punto podemos guardar los cambios al archivo callbacks.c y compilar para verificar que no
existen errores de sintaxis, desde la terminal se debe ejecutar la siguiente sentencia:
make
15.- Ahora adicionamos el cuadro de dialogo Acerca de. Para esto, presionamos el botón de los widgets
adicionales de la paleta de widgets del Glade2, damos clic en el widget correspondiente al cuadro de
dialogo Acerca de (About Dialog). Configuramos las siguientes propiedades:
a) Lo nombramos aboutdialog
b) Como comentario escribimos “Simulación del problema de lectores-escritores”
c) En autores le ponemos nuestro nombre :).
d) Habilitamos la propiedad de auto-destruir
e) Le adicionamos la señal de destroy
16.- Guardamos, construimos y compilamos
17.- Editamos nuevamente el archivo callbacks.c adicionando la siguiente variable global:
GtkWidget * acercade = NULL;
18.- El código de la retrollamada on_toolbuttonAcercade_clicked debe quedar de la siguiente forma:
void
on_toolbuttonAcercade_clicked (GtkToolButton *toolbutton,
gpointer user_data)
{
if(acercade == NULL){
acercade = create_aboutdialog();
}
gtk_widget_show(acercade);
}
Esta función simplemente muestra el widget del cuadro de dialogo Acerca de, siempre y cuando exista
un cuadro de dialogo creado.
19.- El código de la retrollamada on_aboutdialog_destroy debe quedar de la siguiente forma:
M. en C. J. Jesús Arellano Pimentel Abril 2011
Unistmo Ing. en Computación Sistemas Operativos
void
on_aboutdialog_destroy (GtkObject *object,
gpointer user_data)
{
acercade = NULL;
}
20.- Guardamos, compilamos y probamos
make
./lectoresescritores
Hecho lo anterior, se tiene lista la interfaz gráfica de usuario para implementar el problema de los
lectores-escritores. Parra este propósito se deberán realizar los siguientes pasos:
1.- Editar el archivo main.c.
gedit main.c
2.- Añadir el siguiente código después de la inclusión de librerías:
#include <stdlib.h>
#define ESCRITOR 1
#define LECTOR 2
trazar((GtkWidget *)w);
if(rol == ESCRITOR)
{
read(tuberia[0], &c, 1);
sleep(3);
write(tuberia[1], &c, 1);
}
M. en C. J. Jesús Arellano Pimentel Abril 2011
Unistmo Ing. en Computación Sistemas Operativos
sprintf(szRol,"Escritor %d",ale);
}
return TRUE;
}
Los lectores siempre estarán activos, pero un escritor deberá obtener el dato testigo primero antes de
escribir. Aleatoriamente se decide si un proceso es escritor o lector, puede observarse en el código que
si el número aleatorio generado es menor a 9 el proceso será lector, pero si el número aleatorio es 10
será escritor.
4.- El siguiente paso es modificar la función main. Habrá que agregar la declaración de las siguientes
variables:
pid_t pid;
int i;
5.- En la misma función main se deberá crear la tubería, escribir el dato testigo y crear la cantidad de
procesos deseados. Esto se logra mediante el siguiente segmento de código después del bloque de
compilación condicional:
if (pipe(tuberia) == -1)
{
perror("[pipe]");
return -1;
}
M. en C. J. Jesús Arellano Pimentel Abril 2011
Unistmo Ing. en Computación Sistemas Operativos
M. en C. J. Jesús Arellano Pimentel Abril 2011