Resolver el problema de la reentrada

Hace mucho tiempo, escribí un artículo sobre problemas de reingreso

Si en realidad estás en la prueba escrita, el entrevistador pregunta
: ¿qué tiene de malo el siguiente código?

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>

int NUM = 0;

void * PrintNum(void * ptr)
{
    while(NUM++ < 200000000) {
    }
    printf("%s,NUM:%d\n", (char*)ptr, NUM);
    NUM = 0;
}

int main(int argc,char ** argv)
{
    pthread_t thread1 = -1;
    char thread1_name[] = "thread2";
    if(pthread_create(&thread1, NULL, PrintNum, thread1_name)!=0) {
        printf("thread1 creat error\n");
    }

    pthread_t thread2 = -1;
    char thread2_name[] = "thread2";
    if(pthread_create(&thread1, NULL, PrintNum, thread2_name)!=0) {
        printf("thread1 creat error\n");
    }

    void * result1;
    void * result2;
    pthread_join(thread1, &result1);
    pthread_join(thread2, &result2);
}

Este código tiene los siguientes problemas:

Al crear el segundo subproceso, se utilizó el nombre de variable incorrecto.

pthread_create(& thread1 , NULL, PrintNum, thread2_name) 
debe cambiarse a pthread_create(& thread2 , NULL, PrintNum, thread2_name).

En la función PrintNum, no se utiliza ningún mecanismo de sincronización para garantizar que el acceso a la variable global NUM sea seguro para subprocesos. El acceso simultáneo a NUM por varios hilos puede resultar en inconsistencias de datos o errores de programa. Se debe utilizar un mecanismo de sincronización, como un mutex, para garantizar la seguridad de los subprocesos.

En la función PrintNum, se usa un ciclo infinito para simular el tiempo de ejecución del hilo. Esto hará que el subproceso ocupe recursos de la CPU todo el tiempo y afectará el rendimiento del sistema. La función de suspensión debe usarse para esperar un período de tiempo, dejar que el subproceso ingrese al estado bloqueado y liberar recursos de la CPU.

En la función principal, el valor de retorno de la creación y la espera del subproceso no se verifica, y la creación y la espera del subproceso pueden fallar. Debe verificar el valor de retorno y realizar el manejo de errores.

En la función principal, los recursos de subprocesos no se liberan.
Se debe llamar a la función pthread_exit o pthread_cancel después de que se complete la ejecución del subproceso para liberar los recursos del subproceso.

En la función principal, la declaración de devolución no se usa para finalizar el programa, y ​​la declaración de devolución debe usarse para finalizar el programa después de ejecutarlo.

La respuesta anterior es la respuesta que obtuve cuando lancé el código a chatgpt.

Dicho todo esto, este código necesita algunas modificaciones para funcionar correctamente.

Modificar el código

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>

unsigned long int NUM = 0;

void * PrintNum(void * ptr)
{
    unsigned long int count = 0;
    while(NUM++ < 20000) {
      count++;
    }
    printf("%s run %lu in NUM:%lu \n", (char*)ptr, count, NUM);
    NUM = 0;
    pthread_exit(NULL);
}

int main(int argc,char ** argv)
{
    pthread_t thread1 = -1;
    char thread1_name[] = "thread2";
    if(pthread_create(&thread1, NULL, PrintNum, thread1_name)!=0) {
        printf("thread1 creat error\n");
    }

    pthread_t thread2 = -1;
    char thread2_name[] = "thread2";
    if(pthread_create(&thread2, NULL, PrintNum, thread2_name)!=0) {
        printf("thread1 creat error\n");
    }

    void * result1;
    void * result2;
    pthread_join(thread1, &result1);
    pthread_join(thread2, &result2);

    return 0;
}

Ejecutar salida de función

thread2 .....run 18188 in NUM:20001 
thread2 .....run 6812 in NUM:20001

Se encuentra que en el cálculo, el número de ejecuciones de las variables globales por los dos hilos es diferente.

Luego hice todo tipo de retoques

Hasta el final, no completó mi idea original.

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#include <string.h>

unsigned long int g_num = 0;
unsigned long int count_thread1 = 0, count_thread2 = 0;
#define RUN_COUNT 2000
pthread_mutex_t mutex;
pthread_cond_t cond;
int cond_flag = 1;

void * print_num(void * ptr)
{
    while(1) {
        pthread_mutex_lock(&mutex);
        if (g_num >= RUN_COUNT) {
            pthread_mutex_unlock(&mutex);
            break;
        }
        if (strcmp((char*)ptr, "thread1") == 0) {
            if (cond_flag != 1) {
              pthread_cond_wait(&cond, &mutex);
            }
        } else if (strcmp((char*)ptr, "thread2") == 0) {
            if (cond_flag != 2) {
              pthread_cond_wait(&cond, &mutex);
            }
        }
        if (strcmp((char*)ptr, "thread1") == 0) {
            count_thread1++;
            cond_flag = 2;
        } else if (strcmp((char*)ptr, "thread2") == 0) {
            count_thread2++;
            cond_flag = 1;
        }
        g_num++;
        pthread_cond_signal(&cond);
        pthread_mutex_unlock(&mutex);
    }
    if (strcmp((char*)ptr, "thread1") == 0) {
        printf("%s run %lu in g_num:%lu \n", (char*)ptr, count_thread1, g_num);
    } else if (strcmp((char*)ptr, "thread2") == 0) {
        printf("%s run %lu in g_num:%lu \n", (char*)ptr, count_thread2, g_num);
    }
    g_num = 0;
    printf("%s run over \n", (char*)ptr);
    pthread_exit(NULL);
}
int main(int argc,char ** argv)
{
    pthread_mutex_init(&mutex, NULL);
    pthread_cond_init(&cond, NULL);
    pthread_t thread1 = -1;
    char thread1_name[] = "thread1";
    if(pthread_create(&thread1, NULL, print_num, thread1_name)!=0) {
        printf("thread1 creat errorn");
        return -1;
    }
    pthread_t thread2 = -1;
    char thread2_name[] = "thread2";
    if(pthread_create(&thread2, NULL, print_num, thread2_name)!=0) {
        printf("thread1 creat errorn");
        return -1;
    }
    while (1) {
        if (g_num > RUN_COUNT) {
          if (count_thread1 < RUN_COUNT/2) {
              cond_flag = 1;
              pthread_cond_signal(&cond);
          } else if (count_thread2 < RUN_COUNT/2) {
              cond_flag = 2;
              pthread_cond_signal(&cond);
          } else {
            break;
          }
        }
    }
    void * result1;
    void * result2;
    pthread_join(thread1, &result1);
    pthread_join(thread2, &result2);
    pthread_mutex_destroy(&mutex);
    pthread_cond_destroy(&cond);
    return 0;
}

salida de código

thread2 run 1000 in g_num:2000 
thread2 run over 
thread1 run 1001 in g_num:2001 
thread1 run over

En las dos secciones de código anteriores, la primera sección no proporciona ninguna protección para la sección crítica.Cuando los dos subprocesos están programados, el acceso a la sección crítica también es aleatorio.

El segundo párrafo agrega variables de condición y protección de bloqueo, lo que permite que todo el proceso se ejecute regularmente, asegurando así la lógica del software.

Si solo se agrega protección de bloqueo sin agregar variables de condición, solo puede garantizar que haya un acceso de subproceso en un intervalo de tiempo de la sección crítica, pero no se puede garantizar el orden de acceso a la sección crítica.

El uso de variables condicionales en C++, puedes echar un vistazo a estos enlaces

https://en.cppreference.com/w/cpp/thread/condition_variable

https://stackoverflow.com/questions/73543664/no-necesito-bloquear-el-mutex-antes-de-llamar-condición-variablenotificar

https://www.zhihu.com/question/541037047

44b29ca36fcdbb203e848fdb96920777.png

0e80c7eeeb95a863d53fd798ade7350b.jpeg

7348a3d69ee5081a0df3dcc47b57e28b.jpeg

Supongo que te gusta

Origin blog.csdn.net/weiqifa0/article/details/130256502
Recomendado
Clasificación