es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

La cerradura de mutex no funciona como se espera en C.

Intento implementar un proyecto de simulación hospitalaria con hilos, pero el bloqueo de mutex no funciona según lo esperado. El tamaño de registro no debe ser menor que cero; si el tamaño de registro es igual a cero, entonces los hilos deben esperar para ser incrementados. Pero si incremento el número de pacientes (que también son hilos), el tamaño de registro puede ser menor a cero. ¿Por qué está sucediendo esto?

int REGISTRATION_SIZE = 10;
pthread_cond_t condRegister;
pthread_mutex_t mutex;

Paciente:

struct Patient {
    struct Disease disease;
    pthread_t thread_id;
    int thread_num;
    int Hunger_Meter; // Inicializado entre 1 y 100 cuando se crea.
    int Restroom_Meter; // Inicializado entre 1 y 100 cuando se crea.
};

Función de hilo:

void *thread_func(void *p){
    struct Patient *patient = (struct Patient*)p;
    registration();
    return NULL;
}

Método de suspensión:

void sleepForMs(int ms){
    usleep( 1000 *  ms);
}

Uso de hilo:

void registration(struct Patient *p){
    int rnd_wait_time;
    pthread_mutex_lock(&registration_mutex);
    while(REGISTRATION_SIZE == 0){
        rnd_wait_time = generate_rnd_numb(WAIT_TIME) + 1;
        //printf("Patient[%d] waiting for an availabe desk.\n",p->thread_num);
        sleepForMs(rnd_wait_time);
        increase_meters(p);
        checkForRestOrCafe(p);
        pthread_cond_wait(&register_cond,&registration_mutex);
    }
    REGISTRATION_SIZE--;
    printf(" Tamaño de registro: %d \n", REGISTRATION_SIZE);
    pthread_mutex_unlock(&registration_mutex);

    int register_time = generate_rnd_numb(REGISTRATION_TIME) + 1;
    sleepForMs(register_time);

    pthread_mutex_lock(&registration_mutex);
    REGISTRATION_SIZE++;
    pthread_mutex_unlock(&registration_mutex);
    pthread_cond_signal(&register_cond);
}

Main:

int main()
{
    pthread_mutex_init(&mutex, NULL);
    pthread_cond_init(&condRegister, NULL);

    srand(time(NULL));
    int NUMB_OF_PATIENT = 3000;

    struct Disease *diseases = malloc(sizeof(struct Disease));
    diseases = create_diseases();

    struct Patient patient[NUMB_OF_PATIENT];

    create_patients(patient,NUMB_OF_PATIENT,diseases);

    for (int i = 0; i < NUMB_OF_PATIENT; i++)
    {
        pthread_create(&(patient[i].thread_id), NULL, thread_func, (void *)(patient + i));
    }

    //esperar a que todos los hilos terminen
    for (int i = 0; i < NUMB_OF_PATIENT; i++)
    {
        pthread_join(patient[i].thread_id, NULL); 
    }

    pthread_mutex_destroy(&mutex);
    pthread_cond_destroy(&condRegister);
    return (0);
}

Dividir Registro en funciones:

void wait_for_available_resource(struct Patient *p, pthread_mutex_t mutex, pthread_cond_t cond, int resource){
    int rnd_wait_time;
    pthread_mutex_lock(&mutex);
    while(resource == 0){
        rnd_wait_time = generate_rnd_numb(WAIT_TIME) + 1;
        sleepForMs(rnd_wait_time);
        increase_meters(p);
        checkForRestOrCafe(p);
        pthread_cond_wait(&cond,&mutex);
    }
    resource--;
    printf(" Número de recurso: %d \n", resource);
    pthread_mutex_unlock(&mutex);
}

void spend_process_time(int tiempo_necesario){
    int tiempo_transcurrido = generate_rnd_numb(tiempo_necesario) + 1;
    sleepForMs(tiempo_transcurrido);
}

void release_resource(pthread_mutex_t mutex, int numero_de_recurso, pthread_cond_t cond){
    pthread_mutex_lock(&mutex);
    printf("-----------\n");
    printf("número de recurso:%d\n",numero_de_recurso);
    numero_de_recurso++;
    printf("número de recurso:%d\n",numero_de_recurso);
    HOSPITAL_WALLET += REGISTRATION_COST;
    printf("-----------\n");
    pthread_mutex_unlock(&mutex);
    pthread_cond_signal(&cond);
}

void registration(struct Patient *p){
    wait_for_available_resource(p,registration_mutex,register_cond,REGISTRATION_SIZE);
    spend_process_time(REGISTRATION_TIME);
    release_resource(registration_mutex,REGISTRATION_SIZE,register_cond);

}
Tags:  , , , ,

Answer

  1. Avatar for davy.ai

    El problema parece estar en cómo se utiliza el bloqueo de mutex. Varios hilos están accediendo y modificando la variable compartida REGISTRATION_SIZE, y el bloqueo de mutex se utiliza para garantizar que solo un hilo pueda acceder a la variable en cualquier momento dado. Sin embargo, en la implementación actual, el bloqueo de mutex solo se está utilizando para proteger la sección crítica donde se actualiza la variable, y no durante la comprobación de la disponibilidad de recursos.

    Esto significa que hay una condición de carrera donde varios hilos pueden intentar decrementar el tamaño de registro al mismo tiempo, lo que resulta en que el tamaño de registro se vuelva negativo. Para solucionar esto, el bloqueo de mutex debería utilizarse también durante la comprobación de recursos disponibles. La función wait_for_available_resource debería adquirir el bloqueo antes de comprobar la disponibilidad de recursos y liberarlo después de decrementar el recurso.

    Además, la función release_resource debería incrementar la variable de recurso dentro de la sección crítica protegida por mutex y señalar a los hilos en espera solo después de liberar el mutex. Esto asegura que los hilos en espera no sean despertados por la señal mientras el recurso todavía está siendo actualizado.

    Con estos cambios, la implementación debería garantizar que el tamaño de registro no se vuelva negativo incluso cuando varios hilos intentan acceder a él simultáneamente.

    void wait_for_available_resource(struct Patient *p, pthread_mutex_t mutex, pthread_cond_t cond, int *resource){
        int rnd_wait_time;
        pthread_mutex_lock(&mutex);
        while(*resource == 0){
            rnd_wait_time = generate_rnd_numb(WAIT_TIME) + 1;
            sleepForMs(rnd_wait_time);
            increase_meters(p);
            checkForRestOrCafe(p);
            pthread_cond_wait(&cond,&mutex);
        }
        (*resource)--;
        printf(" Número de recurso: %d \n", *resource);
        pthread_mutex_unlock(&mutex);
    }
    
    void spend_process_time(int needed_time){
        int elapsed_time = generate_rnd_numb(needed_time) + 1;
        sleepForMs(elapsed_time);
    }
    
    void release_resource(pthread_mutex_t mutex, int *resource_number, pthread_cond_t cond){
        pthread_mutex_lock(&mutex);
        printf("-----------\n");
        printf("Número de recurso:%d\n",*resource_number);
        (*resource_number)++;
        printf("Número de recurso:%d\n",*resource_number);
        HOSPITAL_WALLET += REGISTRATION_COST;
        printf("-----------\n");
        pthread_mutex_unlock(&mutex);
        pthread_cond_signal(&cond);
    }
    
    void registration(struct Patient *p){
        wait_for_available_resource(p,mutex,condRegister,&REGISTRATION_SIZE);
        spend_process_time(REGISTRATION_TIME);
        release_resource(mutex,&REGISTRATION_SIZE,condRegister);
    }
    

Comments are closed.