web-dev-qa-db-fra.com

Vérifiez si un mutex pthread est verrouillé ou déverrouillé (après qu'un thread se soit verrouillé lui-même)

J'ai besoin de voir si un mutex est verrouillé ou déverrouillé dans une déclaration if, je le vérifie ainsi ...

if(mutex[id] != 2){
    /* do stuff */
}

mais quand je le vérifie, gcc me donne l'erreur suivante:

error: invalid operands to binary != (have 'ptherad_mutex_t' and 'int')

Alors, comment puis-je vérifier si le mutex est verrouillé ou non?

EDIT:

Un composant clé de mon problème est que mes threads (de par leur conception) se verrouillent APRÈS avoir passé le contrôle à un autre thread. Ainsi, lorsque le thread A passe le contrôle au thread B, le thread A est verrouillé, le thread B effectue certaines tâches, puis lorsque le thread B est terminé, il déverrouille le thread A. 

Le problème avec ceci est que si le thread B tente de déverrouiller le thread A et que le thread A n'a pas encore fini de se verrouiller, l'appel à déverrouiller est perdu et le thread A reste verrouillé, ce qui provoque un blocage total.

UPDATE:

J'ai refait mon programme en suivant la suggestion de caf mais je rencontre toujours des problèmes. J'ai moulé mon programme dans la structure caf fournie du mieux que je puisse mais je ne peux même pas dire ce qui cause la fermeture morte ... J'ai créé une nouvelle question ici demandant de l'aide pour mon code.

Vous trouverez ci-dessous une version exploitable de la suggestion de caf. J'ai fait un petit réordonnancement dans la fonction du fil a, sans lequel les fil a et le fil b auraient été verrouillés lors de leur création, dans l'attente d'une condition qui ne pourrait jamais changer.

#include <pthread.h>

int run_a = 0;
pthread_mutex_t lock_a = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond_a = PTHREAD_COND_INITIALIZER;

int run_b = 0;
pthread_mutex_t lock_b = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond_b = PTHREAD_COND_INITIALIZER;

void *a(void *);
void *b(void *);

int main(){
    int status;
    pthread_t thread_a;
    pthread_t thread_b;

    pthread_create(&thread_a, NULL, a, (void *)0);
    pthread_create(&thread_b, NULL, b, (void *)0);

    pthread_join(thread_a, (void **)&status);
    pthread_join(thread_b, (void **)&status);

}

/* thread A */
void *a(void *i){
    while (1) {
        printf("thread A is running\n");
        sleep(1);

        /* unlock thread B */
        pthread_mutex_lock(&lock_b);
            run_b = 1;
            pthread_cond_signal(&cond_b);
        pthread_mutex_unlock(&lock_b);

        /* wait for thread A to be runnable */
        pthread_mutex_lock(&lock_a);
            while (!run_a)
                pthread_cond_wait(&cond_a, &lock_a);
            run_a = 0;
        pthread_mutex_unlock(&lock_a);      
    }
}

/* thread B */
void *b(void *i){
    while (1) {
        /* wait for thread B to be runnable */
        pthread_mutex_lock(&lock_b);
            while (!run_b)
                pthread_cond_wait(&cond_b, &lock_b);
            run_b = 0;
        pthread_mutex_unlock(&lock_b);

        printf("thread B is running\n");
        sleep(1);

        /* unlock thread A */
        pthread_mutex_lock(&lock_a);
            run_a = 1;
            pthread_cond_signal(&cond_a);
        pthread_mutex_unlock(&lock_a);
    }
}
13
ubiquibacon

Les mutex ne sont pas la bonne primitive pour le schéma que vous souhaitez implémenter. Vous devriez utiliser variables de condition :

int run_thread_a = 0;
pthread_mutex_t run_lock_a = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t run_cond_a = PTHREAD_COND_INITIALIZER;

int run_thread_b = 0;
pthread_mutex_t run_lock_b = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t run_cond_b = PTHREAD_COND_INITIALIZER;

/* thread A */
while (1) {
    /* Wait for Thread A to be runnable */
    pthread_mutex_lock(&run_lock_a);
    while (!run_thread_a)
        pthread_cond_wait(&run_cond_a, &run_lock_a);
    run_thread_a = 0;
    pthread_mutex_unlock(&run_lock_a);

    /* Do some work */

    /* Now wake thread B */
    pthread_mutex_lock(&run_lock_b);
    run_thread_b = 1;
    pthread_cond_signal(&run_cond_b);
    pthread_mutex_unlock(&run_lock_b);
}

/* thread B */
while (1) {
    /* Wait for Thread B to be runnable */
    pthread_mutex_lock(&run_lock_b);
    while (!run_thread_b)
        pthread_cond_wait(&run_cond_b, &run_lock_b);
    run_thread_b = 0;
    pthread_mutex_unlock(&run_lock_b);

    /* Do some work */

    /* Now wake thread A */
    pthread_mutex_lock(&run_lock_a);
    run_thread_a = 1;
    pthread_cond_signal(&run_cond_a);
    pthread_mutex_unlock(&run_lock_a);
}

Chaque thread bloquera dans pthread_cond_wait() jusqu'à ce que l'autre thread lui signale de se réveiller. Ce ne sera pas une impasse.

Il peut facilement être étendu à de nombreux threads, en attribuant une int, pthread_cond_t et pthread_mutex_t par thread.

18
caf

Vous pouvez utiliser pthread_mutex_trylock. Si cela réussit, le mutex était non réclamé et vous en êtes maintenant le propriétaire (vous devez donc le relâcher et renvoyer «non caché», dans votre cas). Sinon, quelqu'un le tient.

Je dois souligner cependant que "vérifier si un mutex n'est pas réclamé" est une très mauvaise idée. Il existe des conditions de concurrence inhérentes à ce type de réflexion. Si une telle fonction vous indique, à l'heure t, que le verrou est non caché, cela ne dit absolument rien sur le fait qu'un autre thread ait ou non acquis le verrou à t+1.

Si cela est mieux illustré par un exemple de code, considérez:

bool held = is_lock_held();

if (!held)
{
  // What exactly can you conclude here?  Pretty much nothing.
  // It was unheld at some point in the past but it might be held
  // by the time you got to this point, or by the time you do your
  // next instruction...
}
19
asveikau

Vous ne pouvez pas comparer un pthread_mutex_t avec un int.

Vous pouvez utiliser 

int pthread_mutex_trylock (pthread_mutex_t * mutex);

pour vérifier cela. 

0
Huang F. Lei