Discussion:
Thread stoppt
(zu alt für eine Antwort)
Sven Lanoster
2017-01-02 18:53:51 UTC
Permalink
Moin, moin.

procedure TmyThread.Execute;
var
xDings: IDings;
begin
CoInitialize(NIL);
try
xDings := CreateComObject(CLASS_DINGS) as IDings;
while not Terminated do
; // spannende sachen
finally
xDings := NIL;
CoUnitialize;
end;
end;

Ich debugge in Delphi und gehe mit [F8] die Zeilen durch. Bei
CreateComObject ist Schluss mit Debugging. Die folgenden Zeilen werden
nicht ausgeführt (das erwartete Ergebnis ist auch nicht da). Auch nicht
der finally-Block. Offenbar stellt der Thread die Ausführung an der
Stelle kommentarlos ein.

Achja, die ersten paar Mal, bei denen dieser Thread erzeugt wird,
arbeitet alles wie gewünscht. Aber wenn dann fünf Minuten (oder so) Ruhe
ist und dann ein neuer Thread erzeugt wird, passiert ab CreateComObject
gar nichts mehr, keine Meldung, nichts in den Logs, nichts in der
Windows-Ereignisanzeige.

Was muss man böses getan haben, um diesen Effekt zu erreichen?

Gruß,
Sven.
--
Seltsam? Aber so steht es geschrieben...
Soeren Muehlbauer
2017-01-03 14:06:26 UTC
Permalink
Hi,
Post by Sven Lanoster
procedure TmyThread.Execute;
var
xDings: IDings;
begin
CoInitialize(NIL);
try
xDings := CreateComObject(CLASS_DINGS) as IDings;
while not Terminated do
; // spannende sachen
finally
xDings := NIL;
CoUnitialize;
end;
end;
Ich debugge in Delphi und gehe mit [F8] die Zeilen durch. Bei
CreateComObject ist Schluss mit Debugging. Die folgenden Zeilen werden
nicht ausgeführt (das erwartete Ergebnis ist auch nicht da).
Was muss man böses getan haben, um diesen Effekt zu erreichen?
Was ist CLASS_DINGS genau? Vielleicht ist das Ding nicht threadsafe.

VG. Sören
Sven Lanoster
2017-01-03 18:58:00 UTC
Permalink
Post by Soeren Muehlbauer
Post by Sven Lanoster
Was muss man böses getan haben, um diesen Effekt zu erreichen?
Was ist CLASS_DINGS genau? Vielleicht ist das Ding nicht threadsafe.
IDings ist natürlich fremd, ohne Quelltext und wenn es nach dem
Hersteller geht, soll ich das gar nicht benutzen. Um dort ein Ticket
aufzumachen, wäre es gut, wenn ich etwas mehr Fakten hätte. ;)

Würde Halt(); eigentlich den beobachteten Effekt erzeugen? Ich habe nie
ausprobiert, ob nach Halt(); noch try-finally-blöcke abgearbeitet werden
oder finalization.

Gruß,
Sven.
--
Seltsam? Aber so steht es geschrieben...
Soeren Muehlbauer
2017-01-04 09:03:44 UTC
Permalink
Hi,
Post by Sven Lanoster
Post by Soeren Muehlbauer
Post by Sven Lanoster
Was muss man böses getan haben, um diesen Effekt zu erreichen?
Was ist CLASS_DINGS genau? Vielleicht ist das Ding nicht threadsafe.
IDings ist natürlich fremd, ohne Quelltext und wenn es nach dem
Hersteller geht, soll ich das gar nicht benutzen. Um dort ein Ticket
aufzumachen, wäre es gut, wenn ich etwas mehr Fakten hätte. ;)
Würde Halt(); eigentlich den beobachteten Effekt erzeugen? Ich habe nie
ausprobiert, ob nach Halt(); noch try-finally-blöcke abgearbeitet werden
oder finalization.
Die Frage ist immer noch, was genau CLASS_DINGS ist. Wie Peter schrub,
ist es einerseits interessant, ob das InProcess oder OutOfProcess ist.
Weiterhin wäre interessant, ob der Aufruf nur "hängt" oder ob
tatsächlich der Thread stirbt (Beim Debuggen ist daher in neueren
Versionen das NameThreadForDebugging ganz nützlich). Auch Peters Hinweis
auf CoInitializeEx ist sehr wertvoll.


Wir machen das meist so:

procedure TWorkerThread.Execute;
var
NeedUnInitCOM: Boolean;
begin
NameThreadForDebugging(AnsiString(FName));
NeedUnInitCOM:= Succeeded(CoInitializeEx(nil, COINIT_MULTITHREADED));
try
finally
if NeedUnInitCOM
then CoUninitialize;
end;
end;

COINIT_MULTITHREADED ist bei uns immer in Verwendung, da wir nur COM
Komponenten verwenden die auch Threadsafe sind. In Deinem Fall lohnt
sich der Blick in die Registry, denn dort steht drin, was das für ein
ThreadingModel ist (Unter HKEY_CLASSES_ROOT\CLSID\GUID VON CLASS_DINGS).

Sören
Sven Lanoster
2017-01-06 20:34:48 UTC
Permalink
Post by Soeren Muehlbauer
Post by Sven Lanoster
IDings ist natürlich fremd, ohne Quelltext und wenn es nach dem
Hersteller geht, soll ich das gar nicht benutzen. Um dort ein Ticket
aufzumachen, wäre es gut, wenn ich etwas mehr Fakten hätte. ;)
Ich habe das ganze inzwischen in einen eigenen Prozess ausgelagert und
dort dasselbe Bild. Ein paar Mal läuft das Programm wie gewünscht durch
und nach einer kurzen Pause bleibt es beim nächsten Start hängen.
Ticket ist raus.
Das sieht prima aus. Den Thread nur im Debugger (umzu)benennen ist ein
willkommenes Hilfsmittel. Danke schön!
Post by Soeren Muehlbauer
COINIT_MULTITHREADED ist bei uns immer in Verwendung, da wir nur COM
Komponenten verwenden die auch Threadsafe sind. In Deinem Fall lohnt
sich der Blick in die Registry, denn dort steht drin, was das für
ein ThreadingModel ist (Unter HKEY_CLASSES_ROOT\CLSID\GUID VON
CLASS_DINGS).
Apartment.

Ich warte jetzt erstmal auf die Antwort vom Hersteller.

Gruß,
Sven.
--
Seltsam? Aber so steht es geschrieben...
Peter Below
2017-01-03 18:33:50 UTC
Permalink
Post by Sven Lanoster
Moin, moin.
procedure TmyThread.Execute;
var
xDings: IDings;
begin
CoInitialize(NIL);
Du solltest hier CoInitializeEx verwenden und explizit das gewünschte
Threading-Modell angeben (normalerwiese COINIT_APPARTMENTTHREADED).
Außerdem wirfst Du in völlig verantwortungsloser Weise den Returnkode
weg. Denn solltest Du schon ablegen und inspizieren, denn

* die COM Initialisierung kann durchaus fehlschlagen
* CoUninitialize sollte nur aufgerufen werden, wenn die
Initialisierung auch geklappt hat.
Post by Sven Lanoster
Ich debugge in Delphi und gehe mit [F8] die Zeilen durch. Bei
CreateComObject ist Schluss mit Debugging. Die folgenden Zeilen
werden nicht ausgeführt (das erwartete Ergebnis ist auch nicht da).
Auch nicht der finally-Block. Offenbar stellt der Thread die
Ausführung an der Stelle kommentarlos ein.
d. h. CreateComObject kehrt nicht zurück? Das kann verschiedene
Ursachen haben. Geht es hier um einen in-process oder out-of-process
Server? OLE (z. B. Office) oder plain COM? OLE is leider ziemlich
leicht zu blockieren, je nach Server. Ich hatte selbst schon Fälle wo
MS Word nicht mehr in der Lage war, eine OLE Objekt aus der
Zwischenlage einzufügen oder aus einer Datei zu erzeugen, nur weil
irgend eine andere Anwendung eine Thread mit einem Fenster hatte, der
zu lange keine Messages mehr prozessierte.
Post by Sven Lanoster
Achja, die ersten paar Mal, bei denen dieser Thread erzeugt wird,
arbeitet alles wie gewünscht. Aber wenn dann fünf Minuten (oder so)
Ruhe ist und dann ein neuer Thread erzeugt wird, passiert ab
CreateComObject gar nichts mehr, keine Meldung, nichts in den Logs,
nichts in der Windows-Ereignisanzeige.
Da ist der Server wohl geschlossen worden (das COM subsystem macht das
nach einer gewissen Periode der Inaktivität) und läßt sich nicht wieder
starten.
--
Peter Below
TeamB
Sven Lanoster
2017-01-06 20:18:34 UTC
Permalink
Post by Peter Below
Post by Sven Lanoster
procedure TmyThread.Execute;
var
xDings: IDings;
begin
CoInitialize(NIL);
Du solltest hier CoInitializeEx verwenden und explizit das gewünschte
Threading-Modell angeben (normalerwiese COINIT_APPARTMENTTHREADED).
Ja, das sollte ich.
Post by Peter Below
Außerdem wirfst Du in völlig verantwortungsloser Weise den Returnkode
weg. Denn solltest Du schon ablegen und inspizieren, denn
* die COM Initialisierung kann durchaus fehlschlagen
* CoUninitialize sollte nur aufgerufen werden, wenn die
Initialisierung auch geklappt hat.
Selbstverständlich hast Du völlig Recht.
Post by Peter Below
Post by Sven Lanoster
Ich debugge in Delphi und gehe mit [F8] die Zeilen durch. Bei
CreateComObject ist Schluss mit Debugging. Die folgenden Zeilen
werden nicht ausgeführt (das erwartete Ergebnis ist auch nicht da).
Auch nicht der finally-Block. Offenbar stellt der Thread die
Ausführung an der Stelle kommentarlos ein.
d. h. CreateComObject kehrt nicht zurück?
Ich hatte zuerst den Eindruck, der Thread würde sterben, aber der bleibt
nur stehen. Also: ja.
Post by Peter Below
Geht es hier um einen in-process oder out-of-process
Server? OLE (z. B. Office) oder plain COM? OLE is leider ziemlich
leicht zu blockieren, je nach Server.
Wirklich gute Fragen.
Um das Einbetten von Objekten in andere Objekte (Excell in Word
einbinden oder sowas) geht es bei mir nicht.
Die COM-Objekte, mit denen ich arbeite sind Bestandteil des SDK eines
großen CRM. Damit kann ich mich Anmelden, Daten abfragen, ändern, anlegen.
Post by Peter Below
Post by Sven Lanoster
Achja, die ersten paar Mal, bei denen dieser Thread erzeugt wird,
arbeitet alles wie gewünscht. Aber wenn dann fünf Minuten (oder so)
Ruhe ist und dann ein neuer Thread erzeugt wird, passiert ab
CreateComObject gar nichts mehr, keine Meldung, nichts in den Logs,
nichts in der Windows-Ereignisanzeige.
Da ist der Server wohl geschlossen worden (das COM subsystem macht
das nach einer gewissen Periode der Inaktivität) und läßt sich nicht
wieder starten.
Was genau ist in diesem Kontext der Server?

Gruß,
Sven.
--
Seltsam? Aber so steht es geschrieben...
Peter Below
2017-01-07 09:19:00 UTC
Permalink
Post by Sven Lanoster
Post by Peter Below
Post by Sven Lanoster
Achja, die ersten paar Mal, bei denen dieser Thread erzeugt wird,
arbeitet alles wie gewünscht. Aber wenn dann fünf Minuten (oder
so) Ruhe ist und dann ein neuer Thread erzeugt wird, passiert ab
CreateComObject gar nichts mehr, keine Meldung, nichts in den
Logs, nichts in der Windows-Ereignisanzeige.
Da ist der Server wohl geschlossen worden (das COM subsystem macht
das nach einer gewissen Periode der Inaktivität) und läßt sich nicht
wieder starten.
Was genau ist in diesem Kontext der Server?
Für einen in-process server lädt COM die DLL, die das angeforderte
Objekt implementiert, in den Client-Prozess. Nach einer Periode der
Inaktivität ruft COM die DllCanUnloadNow-Funktion der DLL auf (das ist
einer der Standard entry points die eine COM DLL haben muss). Die DLL
sollte dann S_OK zurückgeben, wenn momentan kein von ihr
implementiertes Objekt existiert, und dann wird die DLL halt wieder aus
dem Prozess entladen, um Speicher und andere Resourcen zu schonen.
--
Peter Below
TeamB
Loading...