Desarrollador Profesional de Juegos Programación III Unidad II introducción a Mutex Secciones críticas.

Slides:



Advertisements
Presentaciones similares
Archivos de Texto. Introducción Los archivos son una secuencia de bits que se guarda en el disco duro. La ventaja de utilizar archivos es que los datos.
Advertisements

III - Gestión de memoria
Curso de Microsoft® Word 2010
I.T.E.S.R.C. Romina Tamez Andrea Martínez Ma. De Lourdes Solís
Estructuras de control
DIAGRAMAS DE FLUJO Y PSEUDOCÓDIGO
DIAGRAMAS DE FLUJO Y PSEUDOCÓDIGO
Informática II Prof. Dr. Gustavo Patiño MJ
Informática II 1 Diego Fernando Serna RestrepoSemestre 2011/2.
Los condicionales IF en PHP Programación en Internet II.
PARADIGMA Es un esquema de pensamiento que nos lleva a concebir las cosas de una manera determinada. el término paradigma puede indicar el concepto de esquema.
La estructura básica de los programas en java, algo a tener en cuenta y que debemos recordar siempre es el archivo debe llevar el nombre de la clase con.
Las variables en PHP Programación en Internet II.
Tema 6: Clases Antonio J. Sierra.
Ingeniero Anyelo Quintero
SCJP SUN CERTIFIED PROGRAMMER FOR JAVA 6. SCJP 6.0 SEMANA OCHO THREADS.
Programación de Computadores
Ingeniero Anyelo Quintero
Semana 5 Subprogramas..
Teoria de grafos.-clase 4
SCJP SUN CERTIFIED PROGRAMMER FOR JAVA 6. SCJP 6.0 SEMANA OCHO THREADS.
1 Planteamiento del problema ¿Tenemos los humanos la capacidad de percibir si nos miran desde atrás? O, más exactamente: ¿Es defendible que existen otras.
Constantes en PHP Programación en Internet II. Constantes en PHP Programación en Internet II Universidad de Guadalajara | Centro Universitario de la Costa.
UNIDAD 3 Conceptos de Sistemas Operativos.
Método Científico.
Unidad III Administración de procesos
Desarrollador Profesional de Juegos Programación III Unidad II Una clase thread para window.
Tema 10a Manejo de archivos. Introducción Un computador puede almacenar grandes cantidades de información. Puede acceder a ella de manera muy rápida.
Comentarios en PHP Programación en Internet II. Comentarios en PHP Programación en Internet II Universidad de Guadalajara | Centro Universitario de la.
Administración de Proyectos de desarrollo de Software Ciclo de vida de un proyecto Enfoque moderno Temas Componentes Directivas Declaraciones globales.
Material de apoyo Unidad 4 Estructura de datos
Aplicación de estructuras de datos
el Desplazamiento (Dx)
Elementos básicos del lenguaje
Unidad II Introducción a la programación en C++
FUNDAMENTOS DE PROGRAMACIÓN Unidad II. Elaborar programas en pseudolenguaje, de acuerdo a requerimientos. Unidad II.
Teoría de Sistemas Operativos Sincronización Procesos Departamento de Electrónica 2º Semestre, 2003 Gabriel Astudillo Muñoz
Elementos básicos del lenguaje
Administrador de procesos
APUNTADORES.
Teoría de Sistemas Operativos Departamento de Electrónica 2º Semestre, 2002 Gabriel Astudillo Muñoz
Tema ‧ Comando - while Repeticiones. Comando while ‧ Un ciclo es cualquier construcción de programa que repite una sentencia ó secuencia de sentencias.
Teoría de Sistemas Operativos Sincronización Procesos
Términos algoritmo diseñar algoritmo implementar algoritmo
INTRODUCCION A LA PROGRAMACION
Se pueden incluir comentarios en cualquier parte de un programa pero deben delimitarse con llaves o con paréntesis y asterisco:
Tema 11 Bases de Datos y el Lenguaje SQL
Introducción a phpMyAdmin
INTERRUPCIONES – ABRAZO MORTAL
Práctica Profesional PHP.
Introducción al lenguaje PROCESSING para ARDUINO
Estructuras de Decisión
Objetivos del tema. Hemos visto lo que es la estructura de un programa, los datos, que esos datos en realidad se convierten en variables de distinto.
Desarrollador Profesional de Juegos Programación III Unidad II Trabajando con bloqueo de datos.
Tipos y ámbitos de grupo (Windows server)
 Las funciones son un conjunto de instrucciones que realizan una tarea específica. En general toman unos valores de entrada, llamados parámetros y proporcionan.
También es conocido como proceso ligero. Es una entidad básica de utilización de CPU y esta formado por un contador de programa, algunos registros y una.
MEMORIA DINÁMICA.
Desarrollador Profesional de Juegos Programación III Unidad II Introdución a threading en windows.
Desarrollador Profesional de Juegos Programación III Unidad I Capturar Excepciones.
Desarrollador Profesional de Juegos Programación III Unidad I Excepciones Tipos.
Mini-video 2 de 5 Materia: Límites de funciones Continuidad de funciones Prácticas con Introducción a Funciones de una variable.
Dado que una colección esta gestionada por una clase dentro del lenguaje que estamos utilizando, y en cierta forma no se tiene un control total.
Ciclos en Visual Basic Yaimira Pérez. Los ciclos son estructuras de repetición que ejecutan una o varias instrucciones durante la cantidad de veces que.
2015-BM5A. Introducción Durante años, los programadores se han dedicado a construir aplicaciones muy parecidas que resolvían una y otra vez los mismos.
Métodos en Java. Estructura de un programa en Java ► La relación con la vida misma la podemos ver en el siguiente comentario: Imaginemos que dos clases.
PROF. RAFAEL MONTENEGRO B. UNELLEZ-APURE Introducci Ó n a los Arreglos (“arrays”) en C++
1 Clase 6: control (1ª parte) iic1102 – introducción a la programación.
Ciclos condicionales y exactos Estructura de control de ciclos
Helpers en ASP.NET MVC3. Introducción Los helpers son una herramienta muy potente para generar nuestro propio código HTML dentro de las vistas. Los helpers.
Transcripción de la presentación:

Desarrollador Profesional de Juegos Programación III Unidad II introducción a Mutex Secciones críticas

Threading en window- Mutex Temas Secciones críticas(critical data) Mutex CreateMutex() ReleaseMutex() CloseHandle()

Mutex Cuando creamos hilos, nos gustaría ser capaces de enviar datos entre ellos, después de todo, queremos mejorar el rendimiento manejando ciertos procesos en sus propios hilos. Esto normalmente significa que un hilo proporcionara datos a otro hilo. Para ello, necesitamos tener dos hilos que compartan la misma memoria, mientras un hilo pueda escribir los datos, y el otro hilo pueda leer estos datos. Esto en sí no es una cosa difícil de hacer, ya que cualquier función tiene acceso a los datos en el ámbito global. Dado que un hilo es sólo una función, los datos a los que una función tiene acceso los tendrá nuestro hilo también. Así que si lo que necesita un hilo para compartir los datos es compartir el scope, ¿cuál es el problema? ¿Qué sucedería si un subproceso intenta escribir los datos, al mismo tiempo que otro subproceso intenta leerlos? La respuesta es, obtendríamos datos corruptos. ¿Cómo podemos evitar esto, si ambos necesitan tener acceso a los mismos datos? Tendríamos que tener algún tipo de señal que le dijera a un hilo que el otro hilo los está utilizando. Si los datos están en uso, esperaremos hasta que se liberen, y si no están en uso, decirle al otro hilo que ahora los estamos utilizando. Estos datos se denominan sección crítica y la herramienta que se utilizará para indicar que la estamos usando se llama mutex.

Mutex Un mutex es una herramienta que va a "bloquear" una sección crítica cuando la estamos usando, y "desbloquear" cuando terminamos de usarla. Cuando queremos realizar un bloqueo, simplemente esperaramos hasta que el mutex no esté bloqueado (porque si esta bloqueado el mutex, significa que otro hilo está utilizando ahora la sección crítica), entonces nosotros mismos bloquearemos, y diremos a todos los demás que ahora estamos utilizando los datos. Sorprendentemente, ya hemos visto la función que utilizaremos para bloquear un mutex... esta en el modulo 1 el la que que espera a que el hilo llegue al final. WaitForSingleObject () hace exactamente eso. Vamos a utilizar tres funciones: – CreateMutex () para crear un mutex y obtener un identificador para el mutex. –WaitForSingleObject () esperará al mutex para que sea liberado o desbloqueado y después bloquearlo. –ReleaseMutex () dará a conocer o desbloquear un mutex que hemos bloqueado.

# include using namespace std; char buffer[128] = "\0"; HANDLE mutexHandle = NULL; bool threadStarted = false; void threadProc() { threadStarted = true; for (int i = 0; i < 10; i++) { WaitForSingleObject( mutexHandle, INFINITE); sprintf( buffer, "%s%d", buffer, i); Sleep(50); ReleaseMutex( mutexHandle); } Ejemplo de Mutex

void main() { mutexHandle = CreateMutex( NULL, false, NULL); HANDLE threadHandle; threadHandle = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE) threadProc, NULL, 0, NULL); while (!threadStarted) { } for (int i = 0; i < 10; i++) { WaitForSingleObject( mutexHandle, INFINITE); cout << buffer << endl; Sleep(50); ReleaseMutex( mutexHandle ); } WaitForSingleObject( threadHandle, INFINITE); CloseHandle( mutexHandle); system("pause"); } Salida Ejemplo de Mutex

Para este ejemplo, vamos a usar datos que ambos hilos van a compartir. Mientras un hilo llena una cadena con un texto y nuestro hilo principal espera hasta que la cadena está llena y luego continúe con su código. Este buffer es nuestro dato crítico, tanto el hilo principal y el threadProc van a leer y escribir en este buffer. Este buffer será nuestra sección critica, es el que vamos a proteger con nuestro mutex. char buffer[128] = "\0"; Entonces, no podemos proteger correctamente nuestros datos sin un mutex. Así que vamos a definir uno. Un mutex es un identificador al igual que nuestros threads. HANDLE mutexHandle = NULL; Este es el identificador que utilizaremos para hacer referencia a nuestro mutex de lectura/escritura a este buffer. Es lo que vamos a proteger con el mutex. Ejemplo de Mutex

Ahora, veamos algún concepto más. Cuando se crea un hilo, la computadora tiene que consumir un tiempo para establecer al proceso en el sistema operativo. Dependiendo de cómo se ha estructurado el hilo, esto podría llevar una cantidad considerable de tiempo. Debido a esto, es que en general se quiere saber exactamente cuándo han arrancado los hilos. Para esto hay un truco que usaremos. Para el hilo que vamos a manejar usaremos un flag que se establece en TRUE al comienzo del ThreadProc. La única manera que el flag sea verdadero, es que el ThreadProc comenzó la ejecución. Luego, simplemente tendrá que esperar en el hilo principal hasta que ese flag sea TRUE antes de continuar. Así que necesitamos un flag para indicar cuando comienza el thread. bool threadStarted = false; Ahora veremos el código de nuestro ThreadProc.

void threadProc() { Recordemos poner el flag en true para que el hilo principal sepa que ha comenzado. threadStarted = true; Ahora tomamos el buffer y le añadimos un número. Esto se va a hacer 10 veces. for (int i = 0; i < 10; i++) { Ahora la viene la parte interesante. Dado que estamos a punto de escribir datos en el buffer, es necesario hacer un bloqueo en el mutex. Una vez que tenemos el mutex bloqueado, nuestro hilo principal no será capaz de escribir o leer desde nuestro buffer. Podemos estar tranquilos, que nuestros datos están seguros. Vamos a bloquear el mutex con WaitForSingleObject (), la misma función que utilizamos para esperar a nuestro hilo finalizar visto en la unidad anterior. //bloqueo del mutex WaitForSingleObject(mutexHandle, INFINITE);

Ahora que tenemos el bloqueo en el mutex, vamos a escribir datos en nuestro buffer. Si usamos el contador i, deberíamos terminar con la cadena con el valor " “ Vamos a utilizar la función sprintf. Lo que estamos haciendo es añadir el valor de i en el final de nuestra cadena. Así que cuando i=0 nuestra cadena está vacía. Si se lo concatenamos al final de la cadena, será "0". Luego, cuando i = 1, nuestra cadena de será "01". Con i = 2, será igual a "012", y así sucesivamente. sprintf(buffer, "%s%d", buffer, i); // concatena i en el buffer Para poder ver las cosas más despacio, vamos a poner a dormir el hilo acá, así podremos observar mejor lo que pasa en la consola de salida. Sleep(50); // dormir 50 milisegundos Terminamos de escribir el buffer. Así que tenemos que liberar el mutex para que otros hilos puedan acceder al buffer. Esto se hace con la función ReleaseMutex(). El argumento de ReleaseMutex () es el mutex handle que queremos desbloquear. Así que pasemos como argumento nuestro mutex handle, y el hilo principal estará libre para acceder al buffer. ReleaseMutex(mutexHandle); // soltar el mutex }

void main() {// el thread principal cout << “Trabajando con Threads y Mutex's"; Antes de poner en marcha nuestro hilo, tenemos que crear el mutex. De lo contrario todas las llamadas que hemos hecho a nuestro mutex no harán nada, porque mutexHandle no contiene un mutex válido. Es importante hacerlo en el orden correcto también. Es fácil pasarse por alto cual es el lugar que se crea el mutex. Debe hacerse antes que el hilo empiece. Esto asegurará que nuestro mutex se creará antes de que alguien intente usarlo. Una vez que creemos nuestro hilo, es necesario que el mutex sea válido o puede haber algunos problemas. Vamos a crear nuestra mutex con CreateMutex (). Para nuestros propósitos, los parámetros no son importantes, para más datos sobre ellos ver: mutexHandle = CreateMutex( NULL, false, NULL); Tenemos el mutex listo para trabajar, y ya definimos nuestro threadProc, así que vamos a iniciar el hilo tal como lo hicimos en el segunda unidad. HANDLE threadHandle; threadHandle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) threadProc, NULL, 0, NULL);

Ahora recordemos el flag de threadStarted, es el momento de usarlo. Dejemos que este hilo espere hasta que nuestro threadProc establezca este valor a true. Luego, continúe normalmente. Esto hará que el hilo espere hasta que nuestro hilo ha empezado a ejecutarse. (al final del la unidad comentaremos este while y veremos qué pasa) while ( !threadStarted) { } Ahora, nuestro hilo se está ejecutando, así que si no hacemos algo con nuestro buffer, nuestro hilo se va a llenar con los datos. Para simplificar, vamos a ver lo que el threadProc está haciendo. Imprimiremos al búfer dentro de threadProc. Pero recordemos, no podemos acceder a los datos en el mismo momento que threadProc, así que tenemos que proteger a nuestros buffer con el mutex. // vamos a imprimir 10 veces al igual que en threadProc for (int i = 0; i < 10; i++) { // bloqueamos el mutex para que threadProc no escriba en el buffer // mientras se está imprimiendo WaitForSingleObject( mutexHandle, INFINITE); cout << buffer << endl; // Imprimir el búfer. Sleep(50); // Al igual que en el threadProc, vamos a dormir este hilo así podemos // observar lo que está pasando. ReleaseMutex( mutexHandle ); / /cuando termina la impresión, liberar la exclusión mutua y permitimos // a threadProc agregue más datos al buffer. }

Esperamos a que nuestro hilo termine antes de salir de la aplicación WaitForSingleObject (threadHandle, INFINITE); Al igual que cualquier variable que creamos manualmente, nuestro sistema ha asignado recursos para nuestro mutex, tenemos que liberarlo con el fin de limpiar la memoria correctamente. Hacemos esto con CloseHandle (). El argumento es el mutexHandle en sí mismo. / / Limpiar nuestro mutex CloseHandle (mutexHandle); / / esperamos a una tecla para salir system("pause"); } La salida será Ahora es tiempo para probar. Primero, vamos a intentar cambiar los valores de sleep en los hilos. Cambiamos el "Sleep (50)" en el threadProc a "Sleep (40)." ¿Se ve un patrón en el que más de un número se inserta antes que el buffer se imprima? Probemos de otra forma. Ponemos sleep(50) en threadProc, y sleep(40) en el hilo principal. ¿Qué pasa ahora? El hilo principal termina de imprimir antes de threadProc, incluso termina con el buffer. Salida

"Entonces, ¿que es el lo importante de todo esto?" Lo que estamos tratando de demostrar es que no se puede depender de la velocidad en la que hilos se ejecutan. En este caso, tenemos suerte que a nuestros hilos de ejecución le lleve más o menos el mismo tiempo. Si ambos valores del sleep fueron 0, puede ocurrir que pasen cientos o miles de veces antes de ver a otro hilo poner más o menos datos en el buffer. Si cambiamos los valores de sleep podemos ver fácilmente esto. Vamos a comentar la instrucción CreateMutex () ahora. Lo que ocurrirá es que no se va a crear el mutex y por lo tanto cualquier llamada a WaitForSingleObject () o ReleaseMutex () no hará absolutamente nada. Esto permitirá a nuestros hilos ejecutarse sin tener que esperarse el uno del otro. Entonces nos gustaría ver que algo salio mal o diferente de que cuando lo hicimos de la forma correcta y protegimos los datos con los mutex. Bien, las posibilidades son pocas ya que cuando manipulamos hilos, es normal que todo siga bien. Esto se debe a que no estamos manipulando el buffer mucho. Además, lo estamos modificando en un solo lugar, en threadProc. Dado que todo lo que el hilo principal hace es la impresión del búfer, sería prácticamente imposible tener un problema. Pero que sucedería si tratamos de modificar los datos del búfer en el hilo principal?

Como ejercicio, escribir la función main () nuevamente para que se elimine un carácter a la vez desde el frente del buffer. Imprimir el contenido del búfer antes y después de quitar el carácter. Una vez modificado, apagar y prender el mutex y cambiar el valor del sleep. Con la combinación adecuada se puede encontrar una manera de romper el flujo de datos.