Después de un breve descanso veraniego, hoy vamos a continuar con la serie introducción al multiprocesamiento en C++. En esta cuarta parte vamos a crear un wrapper alrededor de algunos mecanismos de sincronización.
Más específicamente vamos a crear una clase alrededor de la primitiva de sincronización mutex que ya vimos en el primer artículo de la serie.
Para nuestro wrapper sencillo alrededor de los threads vamos a utilizar solo mutexes por que creo que es lo único que vamos a necesitar.
GThreads con Mutex
Windows tiene una estructura propia llamada mutex
pero no vamos a hacer uso de ellos en nuestra clase. Los objetos mutex
de Windows pueden ser usados entre procesos y son bastante pesados.
Para nuestro cometido no vamos a necesitar la funcionalidad adicional que ofrece ese tipo de objeto así que vamos a implementar una clase de mutex
ligera cuyos objetos puedan ser usados entre diferentes threads pero no entre procesos.
En Windows vamos a utilizar el objeto ligero critical section que es precisamente un mutex
que cubre perfectamente nuestras necesidades.
El Mutex
Vamos a crear un nuevo archivo llamado gmutex.h (Genbeta Mutex) y vamos a escribir una sencilla clase que sirva como wrapper alrededor de las estructuras pthread_mutex_t
en Unix y CRITICAL_SECTION
en Windows.
Para ello vamos a hacer uso como siempre de la compilación condicional a la que ya estamos acostumbrados, vamos a escribir un prototipo de nuestra clase:
class GMutex {
protected:
// Tipos de mutex
#ifdef WIN32
CRITICAL_SECTION m_mutex;
#else
pthread_mutex_t m_mutex;
#endif
};
El Constructor
En ambas APIs es necesario que el objeto mutex
sea iniciado antes de poder utilizarlo, así que vamos a hacerlo en el constructor:
GMutex()
{
#ifdef WIN32
InitializeCriticalSection( &m_mutex );
#else
phtread_mutex_init( &m_mutex, 0 );
#endif
}
El segundo argumento en la función para Unix es supuéstamente un puntero a una estructura de configuración para el mutex
pero no es muy necesario. Al pasar el valor 0 los atributos por defecto son aplicados.
Destructor
Ambas APIs requieren de la destrucción del mutex
cuando hemos terminado de usarlos. Lo lógico es añadirlo al destructor de la clase:
~GMutex()
{
#ifdef WIN32
DeleteCriticalSection( &m_mutex );
#else
pthread_mutex_destroy( &m_mutex );
#endif
}
Adquirir el Mutex
Adquirir un mutex
es una tarea sencilla con ambas APIs:
inline void Lock()
{
#ifdef WIN32
EnterCriticalSection( &m_mutex );
#else
pthread_mutex_lock( &m_mutex );
#endif
}
Liberar el Mutex
Liberarlo es igual de sencillo:
inline void Unlock()
{
#ifdef WIN32
LeaveCriticalSection( &m_mutex );
#else
pthread_mutex_unlock( &m_mutex );
#endif
}
Código completo
El código completo de la clase es el siguiente:
#ifndef _GMutex_h_Como podéis comprobar, nos ha quedado una clase muy sencilla. En el próximo artículo veremos como utilizar esta librería en una demo sencilla.define _GMutex_h@#@
ifdef WIN32
#include <windows.h>
else
#include <pthreads.h>
endif
namespace ThreadLib { class GMutex { public: GMutex() { #ifdef WIN32 InitializeCriticalSection( &m_mutex ); #else pthread_mutex_init( &m_mutex ); #endif }
~GMutex() { #ifdef WIN32 DeleteCriticalSection( &m_mutex ); #else pthread_mutex_destroy( &m_mutex ); #endif } inline void Lock() { #ifdef WIN32 EnterCriticalSection( &m_mutex ); #else pthread_mutex_lock( &m_mutex ); #endif } inline void Unlock() { #ifdef WIN32 LeaveCriticalSection( &m_mutex ); #else pthread_mutex_unlock( &m_mutex ); #endif } protected: #ifdef WIN32 CRITICAL_SECTION m_mutex; #else pthread_mutex_t m_mutex; #endif }
}
endif // _GMutex_h_
En Genbeta Dev | Introducción al multiprocesamiento en C++