Question

Lorsque j'essaie de créer une instance de classe avec une méthode virtuelle et que je la passe à pthread_create, une condition de concurrence critique se produit, l'appelant appelle parfois la méthode de base à la place de la méthode dérivée, comme il se doit. Après avoir googlé pthread vtable race , j'ai découvert qu'il s'agissait d'un comportement assez connu. Ma question est la suivante: quel bon moyen de contourner ce problème?

Le code ci-dessous présente ce comportement pour tous les paramètres d'optimisation. Notez que l'objet MyThread est entièrement construit avant d'être passé à pthread_create.

#include <errno.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct Thread {
    pthread_t thread;

    void start() {
        int s = pthread_create(&thread, NULL, callback, this);
        if (s) {
            fprintf(stderr, "pthread_create: %s\n", strerror(errno));
            exit(EXIT_FAILURE);
        }
    }
    static void *callback(void *ctx) {
        Thread *thread = static_cast<Thread*> (ctx);
        thread->routine();
        return NULL;
    }
    ~Thread() {
        pthread_join(thread, NULL);
    }

    virtual void routine() {
        puts("Base");
    }
};

struct MyThread : public Thread {
    virtual void routine() {

    }
};

int main() {
    const int count = 20;
    int loop = 1000;

    while (loop--) {
        MyThread *thread[count];
        int i;
        for (i=0; i<count; i++) {
            thread[i] = new MyThread;
            thread[i]->start();
        }
        for (i=0; i<count; i++)
            delete thread[i];
    }

    return 0;
}
Était-ce utile?

La solution

Le seul problème ici est que vous supprimez les objets avant que le thread engendré exécute la méthode. Par conséquent, le destructeur d'enfant est déjà déclenché et l'objet n'est plus là.

Cela n'a donc rien à voir avec pthread_create ou quoi que ce soit, c'est votre timing, vous ne pouvez pas créer de fil, lui donner des ressources et les supprimer avant qu'il ait la chance de les utiliser.

Essayez ceci, cela montrera comment les objs sont détruits par le thread principal avant que le thread engendré ne les utilise:

struct Thread {
pthread_t thread;
bool deleted;

void start() {
    deleted=false;
    int s = pthread_create(&thread, NULL, callback, this);
    if (s) {
            fprintf(stderr, "pthread_create: %s\n", strerror(errno));
            exit(EXIT_FAILURE);
    }
}
static void *callback(void *ctx) {
    Thread *thread = static_cast<Thread*> (ctx);
    thread->routine();
    return NULL;
}
~Thread() {
    pthread_join(thread, NULL);
}

virtual void routine() {
    if(deleted){
        puts("My child deleted me");
    }
    puts("Base");
}
};

struct MyThread : public Thread {
virtual void routine() {

}
~MyThread(){
    deleted=true;
}

};

De l’autre côté, si vous ne faites que passer un sommeil en main avant de les supprimer, vous ne rencontrerez jamais ce problème, car le thread créé utilise des ressources valides.

int main() {
const int count = 20;
int loop = 1000;

while (loop--) {
    MyThread *thread[count];
    int i;
    for (i=0; i<count; i++) {
            thread[i] = new MyThread;
            thread[i]->start();
    }
    sleep(1);
    for (i=0; i<count; i++)
            delete thread[i];
}

return 0;
}

Autres conseils

Ne faites pas pthread_join (ou tout autre travail réel) dans destructor.  Ajoutez la méthode join () à Thread et appelez-la avant de supprimer le fil [i] dans main.

Si vous essayez d'appeler pthread_join dans destructor, le thread est peut-être toujours en cours d'exécution  Thread :: routine ().  Ce qui signifie qu’il utilise un objet déjà partiellement détruit .  Qu'est-ce qui va arriver? Qui sait? Espérons que le programme va planter rapidement.

De plus:

  • Si vous souhaitez hériter de Thread, Thread :: ~ Thread doit être déclaré virtuel.

  • Vérifiez toutes les erreurs et gérez-les correctement (ce que BTW ne peut pas être fait dans destructor).

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top