Frage

Im Allgemeinen, wenn Sie haben eine Klasse, die erbt von einer Thread Klasse, und Sie Instanzen dieser Klasse automatisch freigegeben, nachdem Sie fertig sind, ist es in Ordnung, delete this?

Konkretes Beispiel:

In meiner Anwendung habe ich eine Timer Klasse mit einem static Methode genannt schedule.Benutzer nennen es so:

Timer::schedule((void*)obj, &callbackFunction, 15); // call callbackFunction(obj) in 15 seconds

Die schedule Methode erzeugt ein Task Objekt (was den gleichen Zweck wie eine Java-TimerTask-Objekts).Die Task Klasse private der Timer Klasse und erbt von der Thread Klasse (implementiert mit pthreads).So die schedule Methode, die das tut:

Task *task = new Task(obj, callback, seconds);
task->start(); // fork a thread, and call the task's run method

Die Task Konstruktor speichert die Argumente, die für den Einsatz in den neuen thread.In den neuen thread, der Aufgabe run - Methode aufgerufen wird, die wie folgt aussieht:

void Timer::Task::run() {
    Thread::sleep(this->seconds);
    this->callback(this->obj);
    delete this;
}

Beachten Sie, dass kann ich nicht machen, die task Objekt ein stack-Objekt zugeordnet, da der neue thread braucht.Auch, das ich gemacht habe Task Klasse private der Timer Klasse, andere daran zu hindern, es zu verwenden.

Ich bin besonders besorgt, weil das löschen der Task Objekt bedeutet, dass das löschen der zugrunde liegenden Thread Objekt.Der einzige Staat in der Thread Objekt ist eine pthread_t - variable.Gibt es eine Möglichkeit, das könnte wieder kommen, mich zu beissen?Beachten Sie, dass ich nicht mit dem pthread_t Variablen nach den run Methode abgeschlossen ist.

Ich konnte bypass aufrufen delete this durch die Einführung eine Art von Staat (entweder durch ein argument für die Thread::start Methode oder etwas in der Thread Konstruktor) bedeutet, dass die Methode, mit der Gabel zu sollen delete das Objekt, dass es ist das aufrufen der run Methode auf.Aber der code scheint nicht zu funktionieren.

Irgendwelche Gedanken?

War es hilfreich?

Lösung

Ich denke, die ‚diese löschen‘ ist sicher, solange Sie etwas nicht tun, sonst danach in der run () -Methode (weil alle von den Membervariablen des Task-Objekts, usw., wird Speicher an diesem Punkt befreit werden) .

obwohl

ich über Ihr Design wundere ... tun Sie jedesmal, wenn jemand plant ein Timer-Rückruf einen neuen Thread sein wollen Laichen wirklich? Das scheint ziemlich ineffizient zu mir. Sie aussehen könnten, in einem Thread-Pool (oder auch nur einen einzigen persistenten Timer-Thread, der eigentlich nur einen Thread-Pool der Größe einer ist), zumindest eine Optimierung für später. (Oder besser noch, implementieren die Timer-Funktionalität ohne Laichen auf alle zusätzlichen Threads ... wenn Sie eine Ereignisschleife mit einer Timeout-Funktion verwenden (wie select () oder WaitForMultipleObjects ()) ist es möglich, eine beliebige Anzahl unabhängiger multiplexen Timer-Ereignisse innerhalb einer Ereignisschleife des einzelnen Thread)

Andere Tipps

Es gibt nichts besonders schreckliches über delete this; wie lange, wie Sie versichern, dass:

  1. das Objekt ist immer dynamisch zugewiesen werden, und
  2. kein Mitglied des Objekts überhaupt benutzt wird, nachdem es gelöscht.

Der erste von diesen ist das schwierig.Es gibt Schritte, die Sie ergreifen können (z.B.macht das Tor "privat"), die dabei helfen, aber fast alles, was Sie tun können umgangen werden, wenn jemand versucht, hart genug.

Das heißt, Sie wäre wahrscheinlich besser dran mit einer Art von thread-pool.Es neigt zu werden mehr effiziente und skalierbare.

Edit:Wenn ich darüber gesprochen wird umgangen, ich dachte, der code wie diese:

class HeapOnly {
  private:
    HeapOnly () {} // Private Constructor.
    ~HeapOnly () {} // A Private, non-virtual destructor.
  public:
    static HeapOnly * instance () { return new HeapOnly(); }
    void destroy () { delete this; }  // Reclaim memory.
};

Das ist ungefähr so gut an Schutz wie wir können, aber die Fortbewegung ist es trivial:

int main() { 
    char buffer[sizeof(HeapOnly)];

    HeapOnly *h = reinterpret_cast<HeapOnly *>(buffer);
    h->destroy(); // undefined behavior...
    return 0;
}

Wenn es ist direkt, wie diese, diese situation ist ziemlich offensichtlich.Wenn es erstreckte sich über eine größere Anlage, mit (zum Beispiel) ein Objekt, Fabrik, eigentlich der Herstellung der Objekte und den code komplett woanders Zuteilung von Speicher, etc., es kann sehr viel schwieriger geworden, die Spur.

Ich ursprünglich sagte: "es gibt nichts besonders schreckliches über delete this;"und ich stehe dazu-bin ich nicht wieder auf und sagen, es sollte nicht verwendet werden.Ich bin versucht, Sie zu warnen, über die Art von Problemen, die entstehen können, wenn andere code "spielt nicht gut mit anderen."

delete this gibt den Speicher explizit zugewiesen haben für das Gewinde zu verwenden, aber was ist mit den von der OS oder pThreads Bibliothek zugewiesenen Ressourcen, wie der Call-Stack des Threads und Kernel-Thread / Prozessstruktur (falls zutreffend)? Wenn Sie rufen nie pthread_join() oder pthread_detach() und Sie nie die detachstate , ich glaube, Sie noch ein Speicherleck haben.

Es hängt auch davon ab, wie Ihre Thread Klasse verwendet werden soll. Wenn es pthread_join() in seinem destructor nennt, das ist ein Problem.

Wenn Sie pthread_detach() (die Ihr Thread Objekt vielleicht schon tun), und Sie sind vorsichtig, nicht zu dereferenzieren this nach this zu löschen, ich denke, dieser Ansatz praktikabel sein sollte, aber andere Vorschläge einen langlebigeren Thread zu verwenden (oder Threadpool) ist auch eine Überlegung wert.

Wenn alles, was Sie jemals mit einem Task Objekt tun es new ist, start es, und es dann delete, warum werden Sie brauchen, um ein Objekt für das überhaupt? Warum implementieren nicht einfach eine Funktion, die tut, was start tut (minus Objekt Erstellen und Löschen)?

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