Bote de lenguaje C 2: use software puro para reemplazar Mutex mutex

I. Introducción

En el sistema Linux, cuando se ejecutan varios subprocesos en paralelo , si necesita acceder al mismo recurso , debe utilizar las primitivas de sincronización proporcionadas por el sistema operativo para proteger el lugar donde accede al recurso . Las primitivas de sincronización incluyen: mutex, variables de condición, semáforos, etc. El código protegido se denomina "sección crítica" .

Este es un proceso muy formal y básicamente lo hacemos.

¿Se ha preguntado alguna vez cuánto impacto tendrán estas primitivas de sincronización en la eficiencia de ejecución del código ? ¿Es posible no utilizar estos mecanismos proporcionados por el sistema operativo, sino utilizar otros métodos de software puro para lograr el propósito de proteger la sección crítica?

En este artículo, presentamos el algoritmo de Peterson , que puede no ser práctico, pero puede aportarnos algo de reflexión y mejorar nuestras meta-habilidades de programación .

2. Introducción al algoritmo de Peterson

Este algoritmo se utiliza principalmente para resolver el problema de protección de la sección crítica . Sabemos que un tramo crítico debe garantizar tres condiciones:

  1. Acceso mutuamente exclusivo: en cualquier momento, solo un hilo puede ingresar a la sección crítica;
  2. Inactivo dejar entrar: Cuando ningún hilo está ejecutando el código en la sección crítica, debe seleccionar uno de los hilos que se aplican para entrar en la sección crítica y dejarlo entrar en la sección crítica;
  3. Espera limitada: cuando un hilo solicita ingresar a la sección crítica, no puede esperar indefinidamente y debe obtener permiso para ingresar a la sección crítica dentro de un tiempo limitado. En otras palabras, no importa cuán baja sea su prioridad, no debe morir de hambre a la entrada de la zona crítica.

El algoritmo de Peterson es un algoritmo de programación concurrente que implementa bloqueos de exclusión mutua y puede controlar dos subprocesos para acceder a un recurso de usuario compartido sin conflicto de acceso.

El algoritmo de Peterson se basa en los algoritmos LockOne y LockTwo de acceso exclusivo mutuo de dos subprocesos.

  1. El algoritmo LockOne usa una matriz booleana de bandera
  2. LockTwo usa un número entero de turno

Ambos algoritmos logran la exclusión mutua, pero ambos tienen la posibilidad de un punto muerto . El algoritmo de Peterson combina estos dos algoritmos e implementa perfectamente el problema de exclusión mutua de doble hilo con el software.

El algoritmo se explica de la siguiente manera

[Error en la transferencia de la imagen del enlace externo. El sitio de origen puede tener un mecanismo de enlace anti-sanguijuelas. Se recomienda guardar la imagen y subirla directamente (img-1aTmiPkc-1617241079938) (http://iottown.sewain100.cn/iot32_01) ]

Dos variables globales importantes :

Matriz de banderas: Hay 2 elementos booleanos, que representan respectivamente si un hilo se aplica para ingresar al área crítica;
turno: Si ambos hilos se aplican para ingresar al área crítica, esta variable determinará qué hilo debe ingresar al área crítica;

Tres, código de prueba

// 被 2 个线程同时访问的全局资源
static int num = 0; 

BOOL flag[2] = { 0 };
int turn = 0;

void *thread0_routine(void *arg)
{
    for (int i = 0; i < 1000000; ++i)
    {
        flag[0] = TRUE;
        turn = 1;
        while (TRUE == flag[1] && 1 == turn);

        // 临阶区代码
        num++; 
        
        flag[0] = FALSE;
    }
    
    return NULL;
}

void *thread1_routine(void *arg)
{
    for (int i = 0; i < 1000000; ++i)
    {
        flag[1] = TRUE;
        turn = 0;
        while (TRUE == flag[0] && 0 == turn);

        // 临阶区代码
        num++;
        
        flag[1] = FALSE;
    }

    return NULL;
}

El valor inicial del recurso global num es 0 , y los dos programas se incrementan en 1 millón de veces respectivamente , por lo que el resultado final debería ser 2 millones, y el resultado real de la prueba también es verdadero.

Cuarto, el impacto de los bloqueos mutex mutex en la eficiencia de ejecución del código

1. En un solo hilo: el efecto de Mutex mutex en la eficiencia de ejecución del código

for (int i = 0; i < 1000000; ++i)
{
    num++;
}

El código anterior tarda entre 1,8 ms y 3,5 ms .

for (int i = 0; i < 1000000; ++i)
{
    pthread_mutex_lock(&mutex);
    num++;
    pthread_mutex_unlock(&mutex);
}

El código anterior tarda aproximadamente 23,9 ms-38,9 ms . Se puede ver que el efecto de bloquear y desbloquear en la eficiencia de ejecución del código sigue siendo muy obvio .

2. En multiproceso: el efecto de Mutex mutex en la eficiencia de ejecución del código

void *thread0_routine(void *arg)
{
    for (int i = 0; i < 1000000; ++i)
    {
        pthread_mutex_lock(&mutex);
        num++;
        pthread_mutex_unlock(&mutex);
    }
    
    return NULL;
}

void *thread1_routine(void *arg)
{
    for (int i = 0; i < 1000000; ++i)
    {
        pthread_mutex_lock(&mutex);
        num++;
        pthread_mutex_unlock(&mutex);
    }

    return NULL;
}

pérdida de tiempo:

thread0: diff = 125.8ms
thread1: diff = 129.1ms

3. En dos subprocesos, utilice el algoritmo de Peterson para proteger la sección crítica

pérdida de tiempo:

thread1: diff = 1.89ms
thread0: diff = 1.94ms

Cinco, resumen

El algoritmo de Peterson utiliza software puro para proteger la sección crítica, que muestra un mejor rendimiento que el uso del mutex proporcionado por el sistema operativo.

Pero también tiene una desventaja : solo se puede usar en 2 subprocesos, pero como no tiene nada que ver con la plataforma , en algunas ocasiones especiales, ¡puede que se pueda usar para nuestro uso!


Los buenos artículos deben enviarse ; cuanto más compartas, más afortunado eres.


Lectura recomendada

[Lenguaje C]
1. Puntero del lenguaje C: desde el principio subyacente hasta habilidades sofisticadas, con imágenes y códigos para ayudarlo a explicarlo en profundidad
2. El principio de depuración subyacente de gdb original es muy simple
3. Análisis paso a paso: cómo usar C para lograr la programación orientada a objetos
4. Un arma para mejorar la compulsión de código: definición de macro, desde la entrada hasta el abandono
5. Use setjmp y longjmp en lenguaje C para implementar la captura de excepciones y la co-rutina

[Diseño de la aplicación]
1. Todos dicen que la arquitectura del software debe dividirse en capas y en módulos, y cómo hacerlo (1)
2. Todos dicen que la arquitectura del software debe dividirse en capas y en módulos, y cómo hágalo (2)
3. Desarrollo de pasarela de IoT:
proceso de diseño basado en bus de mensajes MQTT (Parte 1) 4. Desarrollo de pasarela de IoT: proceso de diseño basado en bus de mensajes MQTT (Parte 2)
5. Mi método favorito de comunicación entre procesos-mensaje autobús

[Sistema operativo]
1. ¿Por qué las naves espaciales y los misiles prefieren utilizar microcontroladores en lugar de sistemas integrados?

[Internet de las cosas]
1. Esas cosas sobre el cifrado y los certificados
2. Profundice en el lenguaje de secuencias de comandos LUA, le permitirá comprender completamente el principio de depuración

[Tonterías] 1. Basado
en mi experiencia profesional fallida: algunos consejos para los técnicos que son nuevos en el lugar de trabajo

Supongo que te gusta

Origin blog.csdn.net/u012296253/article/details/115366895
Recomendado
Clasificación