Autor |
Beitrag |
Pellaeon
      
Beiträge: 19
|
Verfasst: Mo 05.03.12 22:02
Hiho,
folgende Ausgangslage: ich habe eine DLL. Diese startet einen Thread, welcher erst einmal nichts macht. Wenn eine entsprechende Anforderung eingeht, öffnet der Thread eine VCL-Form modal. Damit das ganze klappt, müssen die Threads synchronisiert werden. Dazu wollte ich TMutex und TConditionVariableMutex benutzen.
Der Hauptthread nimmt den Mutex im Konstruktor in Beschlag. Der Thread wartet per Condition Variable darauf.
Hauptprozess:
-------------
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| procedure TFormThread.showForm(); begin m_show:= true; m_wakeUp:= true; m_condVar.Release();
while m_wakeUp do m_condVar.WaitFor(m_mutex); m_mutex.Acquire(); m_wakeUp:= false; end; |
Thread:
------
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30:
| procedure TFormThread.Execute(); begin Application.Initialize(); Application.Title:='Delphi Window'; m_form:= TViewer.Create(Application);
while True do begin while not m_wakeUp do m_condVar.WaitFor(m_mutex);
m_mutex.Acquire();
m_wakeUp:= false;
if (not m_show) then break;
m_mutex.Release(); m_condVar.Release(); m_form.ShowModal(); end;
Application.Terminate(); m_form.Destroy(); m_form:= nil; m_mutex.Release(); m_condVar.Release(); end; |
Nun soll der Thread erst etwas machen. Darauf soll der Hauptprozess warten und erst wenn der Thread das Signal gibt, weitermachen.. Beim ersten mal klappt das auch immer, aber sobald ich die Condition-Variable mehrmals in beide Richtungen will, klappt das nicht. Irgendwann hängt eine Seite immer. Das starten klappt, aber wenn der Dialog dann beendet wird, sendet der Hauptthread irgendwann ein condVar.release, aber das kommt beim WaitFor nicht an. Die Doku von embarcadero.com ist leider dazu grottig. Der kann man zu diesem Thema nichts weiter entnehmen.
Evtl. hat ja hier noch jemand eine Idee?
VG
Pellaeon
Moderiert von Gausi: B- durch Delphi-Tags ersetztModeriert von Narses: Topic aus Delphi Language (Object-Pascal) / CLX verschoben am Mo 05.03.2012 um 22:24
|
|
Delphi-Laie
      
Beiträge: 1600
Erhaltene Danke: 232
Delphi 2 - RAD-Studio 10.1 Berlin
|
Verfasst: Mo 05.03.12 23:17
Helfen die Stichwörter "criticalsection" und "Synchronisation" weiter?
|
|
delfiphan
      
Beiträge: 2684
Erhaltene Danke: 32
|
Verfasst: Mo 05.03.12 23:21
Du hast eine Race-condition und wohl auch ein paar Blöcke, die als atomare Operation ausgeführt werden müssten, aber nicht werden. Überleg dir die Szenarien nochmals genau. Du kannst dir das mit Context-switches vorstellen (sprich 1 Prozessor) - der Switch kann praktisch an jeder Stelle auftauchen.
Ich hätte das jetzt mit zwei autoresetevents gemacht.
Aber Application in einem Thread sieht ohnehin sehr suspekt aus. Mit viel Glück mag das halbwegs funktionieren, aber es ist sicher nicht darauf ausgelegt...
|
|
jaenicke
      
Beiträge: 19315
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Mo 05.03.12 23:51
Jegliche Zugriffe auf VCL-Objekte, insbesondere das Erstellen von Formularen usw., muss im Hauptthread passieren. Alles andere geht nur zufällig gut, wenn überhaupt...
Dass du also so Probleme bekommst, ist klar und das lässt sich auch nicht anders lösen als sämtliche VCL-/Fenster-/Application-Zugriffe im Kontext des Hauptthreads zu machen.
|
|
Delphi-Laie
      
Beiträge: 1600
Erhaltene Danke: 232
Delphi 2 - RAD-Studio 10.1 Berlin
|
Verfasst: Di 06.03.12 00:05
Moderiert von Narses: Komplett-Zitat des letzten Beitrags entfernt.
Aber dafür gibt es doch das synchronize?! Damit machte ich bisher gute Erfahrungen, ohne wird es allerdings natürlich ein Hornberger Schießen.
Die Bezeichnung "Hauptthread" (o.ä.) gefiel übrigens Luckie überhaupt nicht. Prinzipiell sind die Threads n.m.W. auch gleichberechtigt, es gibt lediglich einen Startthread, der sich aber keinesfalls wie ein roter Faden durch den Programmablauf ziehen muß (oder doch, für die Nachrichtenschleife, damit die visuellen Komponenten bedienbar bleiben?).
|
|
jaenicke
      
Beiträge: 19315
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Di 06.03.12 00:26
Zuletzt bearbeitet von jaenicke am Di 06.03.12 00:27, insgesamt 1-mal bearbeitet
|
|
delfiphan
      
Beiträge: 2684
Erhaltene Danke: 32
|
Verfasst: Di 06.03.12 00:27
In der Delphiwelt gibt es eine globale Variable MainThreadID, welches dem GetCurrentThreadId bei der Initialisierung entspricht. Daher ist der Ausdruck klar definiert und in der System.pas verankert, daher ist der Begriff sicherlich nicht daneben.
//Edit: @jaenicke: Da warst du wohl ein bisschen schneller als ich
Wie auch immer: Wenn du Fensterchen in einem Thread darstellen musst, dann solltest du nicht auf VCL aufbauen. Musst du das denn überhaupt wirklich können? Was ist denn die genaue nicht technische Anforderung, und wieso hast du diese Lösung gewählt?
|
|
Pellaeon 
      
Beiträge: 19
|
Verfasst: Mi 07.03.12 14:20
Ich habe eine Delphi-GUI. Diese soll von einem C#-Programm aus gestartet werden. Dazu habe ich die Delphi-GUI in eine DLL ausgelagert. Da die GUI eine separate Nachrichtenschleife benötigt, muss ich sie in der DLL in einen Thread auslagern, ansonsten würde die DLL das C#-Programm blockieren.
CriticalSection bringt mir nix, da ich keinen Codeabschnitt habe, der von mehreren Threads durchlaufen wird. Es geht eher um ein sinnvolles abstimmen der Threads beim Starten und Beenden der GUI und um Synchronisieren von Datenzugriffen.
Das Auslagern der GUI in einen extra Thread macht nicht unbedingt immer Probleme. In meinem Fall ist die Delphi-GUI ja komplett in dem neuen Thread, ich habe keine Aufteilung das ein Teil in Thread 1 und ein andere in Thread 2 läuft.
VG
Pellaeon Moderiert von Narses: Beiträge zusammengefasst Delphi-Laie hat folgendes geschrieben: | Die Bezeichnung "Hauptthread" (o.ä.) gefiel übrigens Luckie überhaupt nicht. Prinzipiell sind die Threads n.m.W. auch gleichberechtigt, es gibt lediglich einen Startthread, der sich aber keinesfalls wie ein roter Faden durch den Programmablauf ziehen muß (oder doch, für die Nachrichtenschleife, damit die visuellen Komponenten bedienbar bleiben?). |
Soweit ich mich erinner, unterscheidet ein Win32-Programm schon in den Hauptprozess und Threads. Kille ich den Hauptprozess, werden auch die Threads hart beendet.
Dein Gleichheitsprinzip für Threads hat bspw. in Java gültigkeit, soweit ich mich erinner. Da haut das hin, solange ien Thead etwas macht, ist auch die Anwendung noch aktiv.
|
|
jaenicke
      
Beiträge: 19315
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Mi 07.03.12 14:51
|
|
Pellaeon 
      
Beiträge: 19
|
Verfasst: Mi 07.03.12 14:52
|
|
jaenicke
      
Beiträge: 19315
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Mi 07.03.12 15:07
ShowModal blockiert, ja. Aber ein normales Show nicht.
|
|
Pellaeon 
      
Beiträge: 19
|
Verfasst: Mi 07.03.12 16:02
Ein normales show hat aber keine Nachrichten-Schleife!!! Dafür ist ja das Application.run da.
Wenn ich in der DLL nur show aufrufe, startet die GUI, die DLL-Funktion kehrt zurück und die GUI macht nichts, weil die eingehenden Nachrichten nicht verarbeitet werden.
|
|
Oliver Maas
      
Beiträge: 55
|
Verfasst: Mi 07.03.12 18:20
Nabend. Kann sein, dass ich hier auf dem Schlauch stehe, aber ich kapier das mit der DLL schon nicht so recht.
Die Kombination VCL GUI + dll kommt mir etwas seltsam vor (kann aber natürlich trotzdem sein, dass das irgendwie geht).
Kann man von C# nicht sowas wie CreateProcess aufrufen?
Dann hat man eh 2 getrennte Prozesse.
Notfalls kann man sogar was mit Sockets machen (dann schickt man von C# was, und die andere App setzt .Visible := true oder so irgendwie).
Olli
|
|
Pellaeon 
      
Beiträge: 19
|
Verfasst: Mi 07.03.12 19:10
Oliver Maas hat folgendes geschrieben : | Nabend. Kann sein, dass ich hier auf dem Schlauch stehe, aber ich kapier das mit der DLL schon nicht so recht.
Die Kombination VCL GUI + dll kommt mir etwas seltsam vor (kann aber natürlich trotzdem sein, dass das irgendwie geht). |
Warum sollte das nicht gehen und warum sollte das seltsam sein? Man pappt doch auch GUIs in ActiveX-Controls usw. Ist ja dasselbe Prinzip.
Oliver Maas hat folgendes geschrieben : | "Kann man von C# nicht sowas wie CreateProcess aufrufen?
Dann hat man eh 2 getrennte Prozesse. |
Das geht, aber dann habe ich zwei unabhängige Programme, das will ich nicht. Ist ungünstig für die Anwendung, ohne das jetzt ins Detail zu erläutern.
Oliver Maas hat folgendes geschrieben : | Notfalls kann man sogar was mit Sockets machen (dann schickt man von C# was, und die andere App setzt .Visible := true oder so irgendwie). |
Das geht, macht aber gehörig Mehraufwand, wenn ich jetzt erst noch anfangen müsste, mit Sockets zu arbeiten.
|
|
delfiphan
      
Beiträge: 2684
Erhaltene Danke: 32
|
Verfasst: Mi 07.03.12 19:41
Dein .NET Programm hat eine Nachrichtenschleife (angenommen die hat eine GUI). Die reicht doch.
Wenn du keine Nachrichtenschleife hast, dann könntest du noch folgendes probieren: Erzeuge in .NET einen Thread und lade von dort aus deine Delphi-DLL. Im Prinzip sollte dann die ganze Delphi-Initialisierung auf dem Thread stattfinden; für deine Delphi-DLL sieht es aus, als wäre der .NET Thread der MainThread und er sollte der MainThreadID auch die ID des .NET-Threads geben. Ein gutes Gefühl habe ich dabei nicht, aber du könntest es ja mal probieren...
|
|
Pellaeon 
      
Beiträge: 19
|
Verfasst: Mi 07.03.12 21:04
Hiho delphifan,
die reicht nicht. .NET ist doch eine ganz andere GUI-Lib als die VCL. Klar, irgendwo geht es irgendwann zur WinAPI und PeekMessage, TranslateMessage usw., aber das Handling der Fenster, die Zuordnung von Nachrichten zu Funktionen und Methoden, usw. das macht ja alles die entsprechende GUI-Bibliothek. Und die VCL wird das anders machen als das .NET-Framework. Wie soll z.B. .NET eine einkommende Nachricht auf Delphi-Form-Methoden zuordnen.
Mein Problem ist ja nicht die GUI im Thread. Das funktioniert wurnderbar. Mein Problem sind die (rotz) DelpiXE-Synchklassen. Die machen nicht, was ich will. Ich habe ein ähnliches Prinzip mit Mutex und Condition-Variable für einen anderen Sachverhalt in C++ mit Boost programmiert. Das funzt 1A. Die Delphi-Klassen verhalten sich aber anders, die Doku gibt dazu nicht viel Auskunft. Da liegt mein Problem. Ich hab jetzt aber erstmal einen Workaround ohne die Synch-Klassen und nur mit einer einer boolean sowie Sleep() gebaut. Das funktioniert zumindest, auch wenn es mit den Synch-Klassen schöner gewesen wäre.
|
|
jaenicke
      
Beiträge: 19315
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Mi 07.03.12 21:18
Einloggen, um Attachments anzusehen!
|
|
Pellaeon 
      
Beiträge: 19
|
Verfasst: Mi 07.03.12 23:09
Erstmal danke für deine Mühe!
Ich werde das morgen mal mit meiner Form so testen und dann wieder posten, ob es ging oder nicht. Soweit ich mich erinner, dachte ich aber ich hätte das mit nur "show" schon getestet. Naja wie gesagt, ich probier das nochmal und berichte dann 
|
|
delfiphan
      
Beiträge: 2684
Erhaltene Danke: 32
|
Verfasst: Do 08.03.12 09:07
Pellaeon hat folgendes geschrieben : | Klar, irgendwo geht es irgendwann zur WinAPI und PeekMessage, TranslateMessage usw., (...) Wie soll z.B. .NET eine einkommende Nachricht auf Delphi-Form-Methoden zuordnen. |
Du gibst dir die Antwort ja gleich selbst. Über DispatchMessage werden die richtigen Callbacks aufgerufen -- wenn das eine Message für einen Delphi-Knopf ist, dann geht es ins Delphi rein.
Du kannst von Delphi aus ja auch eine Win32 MessageBox anzeigen und deine Delphi-UI im Hintergrund friert auch nicht ein. Das liegt daran, dass auch die Win32 MessageBox eine Nachrichtenschleife hat.
|
|
Delphi-Laie
      
Beiträge: 1600
Erhaltene Danke: 232
Delphi 2 - RAD-Studio 10.1 Berlin
|
Verfasst: Do 08.03.12 11:07
Pellaeon hat folgendes geschrieben : | Soweit ich mich erinner, unterscheidet ein Win32-Programm schon in den Hauptprozess und Threads. Kille ich den Hauptprozess, werden auch die Threads hart beendet. |
Meinst Du tatsächlich "Hauptprozess" oder doch eher "Hauptthread"? Es gibt nämlich keinen Hauptprozeß, und wenn der Prozeß beendet wird, dann logischerweise auch alle seine Threads (für die er ja eine Art Container darstellt).
Pellaeon hat folgendes geschrieben : | Dein Gleichheitsprinzip für Threads hat bspw. in Java gültigkeit, soweit ich mich erinner. Da haut das hin, solange ien Thead etwas macht, ist auch die Anwendung noch aktiv. |
Das ist doch dann aber ein Konstruktionsmerkmal von Windows, das Java ausnutzt, denn Threads gibt es auch außerhalb Javas und seiner Compilate. Ob Delphi das für seine Compilate auch umzusetzen imstande ist, weiß ich nicht.
|
|
|