Frage

Wenn ich versuche, eine Klasseninstanz mit einer virtuellen Methode zu erstellen und geben sie nicht an pthread_create, erhalte ich eine Race-Bedingung, den Anrufer verursachen manchmal rufen Sie die Basismethode anstelle der abgeleiteten Verfahren, wie es sollte. Nach pthread vtable race googeln, fand ich heraus, das ziemlich gut bekanntes Verhalten. Meine Frage ist, was einen guten Weg, um es zu bekommen?

Der folgende Code zeigt dieses Verhalten zu jeder Optimierungseinstellung. Beachten Sie, dass die MyThread Objekt vollständig, bevor sie weitergegeben aufgebaut ist, 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;
}
War es hilfreich?

Lösung

Das einzige Problem dabei ist, dass Sie die Objekte löschen, bevor der erzeugte Thread das Verfahren ausführt, so zu diesem Zeitpunkt bereits das Kind destructor gefeuert und das Objekt ist nicht mehr da.

So ist es nichts mit pthread_create zu tun hat, oder was auch immer, sein Ihr Timing, können Sie nicht einen Thread erzeugen, ihm einige Ressourcen geben und sie löschen, bevor er die Chance, mit sich hat.

Versuchen Sie dieses, es wird zeigen, wie die objs von Haupt-Thread zerstört werden, bevor erzeugte Thread nutzt sie:

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;
}

};

In der anderen Seite, wenn Sie nur einen Schlaf in Haupt legen, bevor sie gelöscht werden Sie nie das Problem haben, weil der erzeugte Thread gültige Ressourcen verwendet.

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;
}

Andere Tipps

Sie nicht tun pthread_join (oder jede andere echte Arbeit) in destructor.  In join () -Methode Fädeln und nennt es vor löschen Thread [i] in main.

Wenn Sie versuchen, in destructor zu nennen pthread_join kann Thread noch seine Ausführung  Thread :: Routine ().  Was bedeutet, dass es Ziel ist, die mit ist bereits teilweise zerstört .  Was wird passieren? Wer weiß? Hoffentlich Programm wird schnell zum Absturz bringen.


Zusätzlich:

  • Wenn Sie von Thema erben wollen, Gewinde :: ~ Thema sollte virtuell deklariert werden.

  • Überprüfen Sie für alle Fehler und behandeln sie richtig (was übrigens nicht innerhalb destructor erfolgen).

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top