10.5. Finalización de tareas

En los ejemplos anteriores, hemos visto el uso de una "bandera de terminación" o de la interfaz Cancelable para finalizar una tarea. Este es un enfoque razonable para el problema. Sin embargo, en algunas ocasiones la tarea tiene que ser finalizada más abruptamente. En esta sección, aprenderá sobre las cuestiones y problemas de este tipo de finalización.

Primeramente, veamos en un ejemplo que no sólo demuestra el problema de la finalización sino que, además, es un ejemplo adicional de comparición de recursos. Para mostrar el ejemplo, primero necesitaremos resolver el problema de la colisión de iostream.

10.5.1. Prevención de coliciones en iostream

FIXME: dos versiones: Podría haberse dado cuenta en los anteriores ejemplos que la salida es confusa en algunas ocasiones. Los iostreams de C++ no fueron creados pensando en el sistema de hilos, por lo que no hay Puede haberse dado cuenta en los ejemplos anteriores que la salida es FIXMEconfusa. El sistema iostream de C++ no fue creado con el sistema de hilos en mente, por no lo que no hay nada que prevenga que la salida de un hilo interfiera con la salida de otro hilo. Por ello, debe escribir aplicaciones de tal forma que sincronicen el uso de iostreams.

Para solucionar el problema, primero necesitamos crear un paquete completo de salida y, después, decidir explícitamente cuando intentamos mandarlo a la consola. Una sencilla solución pasa por escribir la informacion en un ostringstream y posteriormente utilizar un único objeto con un mutex como punto de salida de todos los hilos, para evitar que más de un hilo escriba al mismo tiempo:

//: C11:Display.h
// Prevents ostream collisions.
#ifndef DISPLAY_H
#define DISPLAY_H
#include <iostream>
#include <sstream>
#include "zthread/Mutex.h"
#include "zthread/Guard.h"

class Display { // Share one of these among all threads
  ZThread::Mutex iolock;
public:
  void output(std::ostringstream& os) {
    ZThread::Guard<ZThread::Mutex> g(iolock);
    std::cout << os.str();
  }
};
#endif // DISPLAY_H ///:~

Listado 10.24. C11/Display.h


De esta manera, predefinimos la función estandar operator<<() y el objeto puede ser construido en memoria utilizando operadores habituales de ostream. Cuando una tarea quiere mostrar una salida, crea un objeto ostringstream temporal que utiliza FIXME. Cuando llama a output(), el mutex evita que varios hilos escriban a este objeto Display. (Debe usar solo un objeto Display en su programa, tal y como verá en los siguientes ejemplos.)

Todo esto muestra la idea básica pero, si es necesario, puede construir un entorno más elaborado. Por ejemplo, podría forzar el requisito de que solo haya un objeto Display en un programa haciéndolo Singleton. (La librería ZThread tiene una plantilla Singleton para dar soporte a Singletons).