Frage

Ich wollte durch einen Legacy-Code und fand den folgenden Ausschnitt:

MyClass::~MyClass()
{
   EnterCriticalSection(&cs);

//Access Data Members, **NO Global** members are being accessed here


  LeaveCriticalSection(&cs);
}

Ich frage mich, wird es durch Zufall helfen, den destructor zu schützen?

Betrachten wir ein Szenario:

1. Thread1 - About to execute any of the member function which uses critical section
2. Thread2-  About to execute destructor.

Wenn die Reihenfolge der Ausführung 1 => 2, dann könnte es funktionieren. Aber was, wenn die Reihenfolge umgekehrt wird?

Ist es ein Design-Problem?

War es hilfreich?

Lösung

Der destructor sollte nicht aufgerufen werden, wenn das Objekt in Gebrauch ist . Wenn Sie mit einer solchen Situation zu tun haben, braucht es eine grundlegende fix . Allerdings könnte will, dass der destructor eine andere Sache verändern (die die Klasse in keinem Zusammenhang wird zerstört) und es könnte einen kritischen Abschnitt benötigt (z wie Erniedrigen einen global Zähler).

Andere Tipps

Ich denke, dass Sie ein grundlegenderes Problem haben. Es sollte nicht legal sein Ihr Objekt auf einem Thread zu zerstören, während ein anderer Thread noch Member-Funktionen aufrufen. Das ist an sich falsch.

Auch wenn Sie erfolgreich schützen Sie Ihren destructor mit kritischen Abschnitten, was passiert, wenn der andere Thread den Rest der Funktion beginnt mit der Ausführung? Es wird dabei auf ein gelöschtes Objekt, das (auf seine Zuteilung je nach Standort) wird Müll Speicher oder einfach ein ungültiges Objekt sein.

Sie müssen Ihren Code ändern, um das Objekt zu gewährleisten, während nicht zerstört noch in Gebrauch.

Wenn Sie globale Variablen zugreifst Sie könnten Thread-Sicherheit benötigen, ja

zB. Mein „Window“ Klasse fügt sich in die Liste „knownWindows“ im Konstruktor und entfernt sich in der destructor. „KnownWindows“ muss THREAD sein, so dass sie beide einen Mutex sperren, während sie es tun.

Auf der anderen Seite, wenn Ihr destructor nur Mitglieder des Objektes greift zerstört, haben Sie ein Design-Problem.

Define "thread-safe". Dies sind möglicherweise die beiden schlecht verstandenen Worte in modernen Computing.

Aber wenn es eine Möglichkeit, dass der destructor ist zweimal von zwei verschiedenen Threads eingegeben wird (wie die Verwendung von symchronisation Objekten impliziert) Ihr Code in tief doo-doo. Die Objekte, die das Objekt löschen, die Sie fragen, sollte dies die Verwaltung - es ist (wahrscheinlich) auf dieser Ebene, dass die Synchronisation stattfindet, werden sollte.

Ich habe einen Fall mit ACE-Threads gesehen, wo der Faden auf einem ACE_Task_Base Objekt ausgeführt wird, und das Objekt wird von einem anderen Thread zerstört. Die destructor erwirbt eine Sperre und benachrichtigt die enthaltenen Gewinde, kurz vor einer Bedingung warten. Der Faden, der auf dem ACE_Task_Base Signal läuft signalisiert den Zustand am Ausgang und läßt den destructor vollständig und den ersten Fadenausgang:

class PeriodicThread : public ACE_Task_Base
{
public:
   PeriodicThread() : exit_( false ), mutex_()
   {
   }
   ~PeriodicThread()
   {
      mutex_.acquire();
      exit_ = true;
      mutex_.release();
      wait(); // wait for running thread to exit
   }
   int svc()
   {
      mutex_.acquire();
      while ( !exit_ ) { 
         mutex_.release();
         // perform periodic operation
         mutex_.acquire();
      }
      mutex_.release();
   }
private:
   bool exit_;
   ACE_Thread_Mutex mutex_;
};

In diesem Code muss die destructor Thread-Sicherheit Techniken verwenden, um sicherzustellen, dass das Objekt nicht vor dem Gewinde zerstört wird, der ausgeführt wird SVC () beendet.

wird nicht einen Unterschied machen. Wenn, wie Sie sagen, ist die Reihenfolge der Anrufe umgekehrt dann sind rufen Sie eine Member-Funktion auf einem zerstörten Objekt und das wird zum Scheitern verurteilt. Die Synchronisation kann nicht den logischen Fehler beheben (für den Anfang, das den Mitgliedsfunktionsaufruf ein Sperrobjekt zu erwerben, würde versuchen, das worden ist zerstört).

Ich schließe ich den Kommentar von Neil Butterworth. Absolut, die Entitäten verantwortlich für das Löschen und das myclass Zugriff sollte eine Kontrolle über diese haben.

Diese Synchronisation wird tatsächlich von dem Moment an beginnt das Objekt vom Typ MyClass erstellt wird.

Ihre Kommentare sagt: „ keine globale Mitglieder hier zugegriffen wird“ so dass ich nicht erraten würde. Nur der Thread, der ein Objekt erstellt sollte es zerstören, so von dem, was andere Thread Sie es zu schützen seien?

Ich mag geordnete Schöpfung und Zerstörung selbst, wo nur ein einziges Objekt, das jemals ein anderes Teilobjekt besitzt, und jedes andere Objekt mit einem Verweis auf dieses Teilobjekt ist ein Abkömmling weiter unten im Baum. Wenn eine dieser Unterobjekte verschiedenen Threads darstellen, dann haben sie dafür gesorgt, abgeschlossen ist, bevor die Zerstörung des Baumes geht auf.

Beispiel:

  • main () erstellen Objekt A
    • Objekt A enthält Objekt B
      • Objekt B enthält Objekt C
        • Objekt C erzeugt einen Thread, der Objekte A und B
        • Zugriffe
        • Objekt C Destruktor läuft, warten auf ihren Faden beenden
      • Objekt B destructor läuft
    • Objekt A Destruktor läuft
  • main () kehrt

Die Destruktoren für Objekt A und B brauchen nicht gar über Threads zu denken, und das Objekt nur C Destruktor einige Kommunikationsmechanismus implementieren muss (auf ein Ereignis warten, zum Beispiel) mit dem Faden wählte es sich zu erstellen.

Sie können nur in Schwierigkeiten geraten, wenn Sie ohne Spur zu halten, um Ihre Objekte zu beliebigen Themen Austeilen Referenzen (Zeiger) beginnen, wenn diese Threads erstellt und zerstört, aber wenn man das dann tun sollten Sie mit Referenzzählung werden es ist, und wenn Sie dann zu spät durch die Zeit der Destruktor aufgerufen wird. Wenn es zu einem Objekt noch eine Referenz ist, dann hätte niemand auch nur versucht, seine destructor aufzurufen.

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