Introducción al multiprocesamiento en C++ IV: sincronización con Mutex

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_

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_

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.


En Genbeta Dev | Introducción al multiprocesamiento en C++

Portada de Genbeta