Delphi: Debug kritische Abschnitt hängt von Call-Stack von laufenden Threads auf lock „failure“ Berichterstattung

StackOverflow https://stackoverflow.com/questions/3719841

Frage

Ich bin auf der Suche nach einer Möglichkeit, einen seltener Delphi 7 kritische Abschnitt (TCriticalSection) hängen / Deadlock zu debuggen. In diesem Fall, wenn ein Thread auf einem kritischen Abschnitt wartet auf mehr als etwa 10 Sekunden, würde Ich mag einen Bericht mit dem Stack-Trace sowohl dem Thread gerade in den kritischen Abschnitt und auch die Gewindesicherung erzeugen, die in der Lage ist fehlgeschlagen seine den kritischen Abschnitt zu sperren nach 10 Sekunden warten. Es ist OK, dann, wenn eine Ausnahme ausgelöst wird oder die Anwendung beendet wird.

Ich würde es vorziehen, mit kritischen Abschnitten fortzusetzen, anstatt mit anderen Synchronisations Primitiven, wenn möglich, aber wechseln kann bei Bedarf (wie eine Timeout-Funktion zu erhalten).

Wenn das Werkzeug / Methode arbeitet zur Laufzeit außerhalb des IDE, dass ein Bonus, da diese nur schwer auf Nachfrage zu reproduzieren. Im seltenen Fall, dass ich um den Stillstand in der IDE duplizieren, wenn ich versuche, das Debuggen zu starten, um Pause, nur die IDE sitzen dort nichts zu tun, und werden nie zu einem Zustand, wo ich Threads oder Call Stacks ansehen kann. Ich kann das laufende Programm neu, though.

Update: In diesem Fall bin ich nur mit einem kritischen Abschnitt Umgang und 2 Fäden, so dass dies wahrscheinlich nicht ein Schloss Bestell Problem. Ich glaube, es ist ein falscher verschachtelter Versuch, die Sperre auf zwei verschiedene Threads, die Ergebnisse in einer Sackgasse zu gelangen.

War es hilfreich?

Lösung

Sie sollten Ihr eigenes Schloss Objektklasse erstellen und verwenden. Es kann unter Verwendung von kritischen Abschnitten oder mutexes implementiert, je nachdem, ob Sie diese oder nicht debuggen möchten.

Ihre eigene Klasse erstellen hat einen zusätzlichen Vorteil: Sie können eine Sperrhierarchie implementieren und eine Ausnahme auslösen, wenn sie verletzt wird. Deadlocks passieren, wenn Schlösser sind nicht genau die gleiche Reihenfolge aufgenommen, jedes Mal. eine Sperrstufe zu jedem Schloss zuordnen macht es möglich, dass die Schlösser in der richtigen Reihenfolge getroffen werden, zu überprüfen. Sie könnten die aktuelle Sicherungsstufe in einem threadvar speichern und ermöglichen sperrt nur genommen werden, die eine geringere Sperrstufe haben, sonst heben Sie eine Ausnahme. Dadurch werden alle Verletzungen fangen, auch wenn kein Deadlock geschieht, so sollte es Ihre Debuggen viel beschleunigen.

Wie der Stack-Trace des Threads für immer, es gibt viele Fragen hier auf Stack-Überlauf Umgang mit diesem.

Aktualisieren

Sie schreiben:

In diesem Fall ist ich nur mit einem kritischen Abschnitt Umgang und 2 Fäden, so dass dies wahrscheinlich nicht ein Schloss Bestell Problem. Ich glaube, es ist ein falscher verschachtelter Versuch, die Sperre auf zwei verschiedene Threads, die Ergebnisse in einer Sackgasse zu gelangen.

Das kann nicht die ganze Geschichte. Es gibt keine Möglichkeit, mit zwei Fäden und ein einzigen kritischen Abschnitt allein unter Windows in einer Sackgasse, weil kritische Abschnitte können dort durch einen Thread rekursiv erworben werden. Es hat eine anderen Sperrmechanismus beteiligt ist, wie zum Beispiel des SendMessage() Aufruf werden.

Aber wenn man wirklich nur mit zwei Threads zu tun hat, dann einer von ihnen hat das Haupt / VCL / GUI-Thread sein. In diesem Fall sollten Sie die MadExcept „Hauptthread freeze checking“ Funktion verwenden können. Er wird versuchen, eine Nachricht an den Haupt-Thread zu senden, und nicht nach einer anpassbares Zeit ohne die Nachricht gehandhabt abgelaufen ist. Wenn Ihr Hauptthread auf dem kritischen Abschnitt blockiert, und der andere Thread auf einer Nachrichtenverarbeitung Anruf blockiert dann MadExcept sollte diese in der Lage sein, zu fangen und geben Ihnen einen Stack-Trace für beide Threads.

Andere Tipps

Dies ist keine direkte anwer auf Ihre Frage, aber etwas, das ich lief in letzter Zeit, die mich hatte (und ein paar Kollegen) für eine Weile ratlos.

Es war ein intermittierender Faden hängen, einen kritischen Abschnitt beteiligt und sobald wir die Sache wussten, es war sehr offensichtlich, und gab wir alle einen „d'oh“ Moment. Allerdings hat es einige ernsthafte Jagd nehmen zu finden (das Hinzufügen von mehr und mehr Trace-Logging der säumige Anweisung zu lokalisieren) und das ist, warum ich dachte, dass ich es nennen würde.

Es war auch auf einem kritischen Abschnitt betreten. Ein anderer Thread hatte in der Tat, dass die kritischen Abschnitt erworben. Eine tote Sperre als solche schien nicht die Ursache zu sein, da es nur eine kritischer Abschnitt beteiligt war, so dass es mit dem Erwerb von Schlössern in einer anderen Reihenfolge keine Probleme sein könnte. Der Thread den kritischen Abschnitt hält, sollte einfach haben fortgesetzt und dann die Verriegelung gelöst, die anderen Threads erlaubt, sie zu erwerben.

Am Ende stellte sich heraus, dass der Thread die Sperre hält, schließlich wurde die ItemIndex eines (IIRC) Combobox Zugriff ziemlich harmlos wie es scheint. Leider, dass ItemIndex immer auf Nachrichtenverarbeitung angewiesen. Und der Faden für die Sperre warten war die Hauptanwendungsthread ... (nur für den Fall jemand Wunder: der Haupt-Thread macht die ganze Nachrichtenverarbeitung ...)

Wir haben vielleicht viel früher daran gedacht, wenn es ein wenig mehr von Anfang an klar gewesen war, dass die vcl beteiligt war. Allerdings begann es in nicht-ui zugehörigen Code und vcl Beteiligung nur abzeichneten Instrumentierung nach dem Hinzufügen (Eingabe - Ausfahrt Tracing). Entlang der Aufrufstruktur und zurück durch alle ausgelösten Ereignisse und ihre Handler an den UI-Code nach oben

Hoffe nur, dass diese Geschichte von Hilfe zu jemandem mit einem geheimnisvollen Hang konfrontiert sein wird.

Verwenden Mutex statt Critical Section. Es gibt einen kleinen Unterschied zwischen mutexes und kritische Abschnitte - kritische Abschnitte sind effektiver während mutexes flexibler sind. Sie kann einfach zwischen mutexes und kritischen Abschnitten, beispielsweise unter Verwendung mutexes in Debug-Version.

für kritischen Abschnitt verwenden wir:

var
  FLock: TRTLCriticalSection;

  InitializeCriticalSection(FLock);  // create lock
  DeleteCriticalSection(FLock);      // free lock
  EnterCriticalSection(FLock);       // acquire lock
  LeaveCriticalSection(FLock);       // release lock

das gleiche mit Mutex:

var FLock: THandle;

  FLock:= CreateMutex(nil, False, nil);  // create lock
  CloseHandle(FLock);                    // free lock
  WaitForSingleObject(FLock, Timeout);   // acquire lock
  ReleaseMutex(FLock);                   // release lock

Sie können Timeouts verwenden (in Millisekunden; 10000 für 10 Sekunden) mit mutexes durch die Implementierung acquire-Lock-Funktion wie folgt aus:

function AcquireLock(Lock: THandle; TimeOut: LongWord): Boolean;
begin
  Result:= WaitForSingleObject(Lock, Timeout) = WAIT_OBJECT_0;
end;

Sie können auch statt TryEnterCriticalSection Kritische Abschnitte mit dem EnterCriticalSection API verwenden.

Wenn Sie TryEnterCriticalSection verwenden und die Lock-Acquisition ausfällt, False die API zurückkehrt und Sie können mit dem Scheitern in irgendeiner Weise sehen Sie fit, anstatt nur Sperren des Themas befassen.

So etwas wie

while not TryEnterCriticalSection(fLock) and (additional_checks) do
begin
  deal_with_failure();
  sleep(500); // wait 500 ms
end;

Zu beachten ist, dass Delphi TCriticalSection Anwendungen EnterCriticalSection so, wenn Sie diese Klasse optimieren, müssen Sie Ihre eigene Klasse zu tun, oder Sie werden mit dem kritischen Abschnitt zu tun haben Initialisierung / Deinitialisierung.

Wenn Sie auf etwas mit einem Timeout zu warten, in der Lage sein wollen, können Sie versuchen, Ihre kritischen Abschnitt mit einem TEvent Signal ersetzt. Sie können auf das Ereignis warten sagen, gib es einen Timeout-Länge, und prüfen Sie den Ergebniscode. Wenn das Signal gesetzt wurde, dann können Sie fortfahren. Falls nicht, wenn es Zeitüberschreitung, heben Sie eine Ausnahme.

Zumindest das ist, wie ich es in D2010 tun würde. Ich bin mir nicht sicher, ob Delphi 7 hat TEvent, aber es wahrscheinlich der Fall ist.

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