Synchronize(), TThread und Bibliotheken

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
Targion
Beiträge: 688
Registriert: Mi 3. Okt 2007, 21:00
OS, Lazarus, FPC: Linux (L 0.9.29 FPC 2.4.2)
CPU-Target: x86_64

Synchronize(), TThread und Bibliotheken

Beitrag von Targion »

Hallo!
In einer meiner Libs arbeitet ein TThread, der Callbacks zum Hauptprogramm aufruft. Damit es da keine Probleme gibt, habe ich die Teile mit Callbacks mit dem Hauptthread Synchronisiert (über Synchronize).
Jetzt hängt sich der TThread in der Lib aber immer genau dann auf, wenn ein Synchonize() aufgerufen wird. Is meine Vermutung korrekt, dass Synchronize() in der Lib gar nicht funktionieren kann, weil es keinen Hauptthread gibt bzw. auf diesen nicht zugegriffen werden kann?
Was wäre dann der beste weg, um den Callback vernünftig auszuführen?

mschnell
Beiträge: 3444
Registriert: Mo 11. Sep 2006, 10:24
OS, Lazarus, FPC: svn (Window32, Linux x64, Linux ARM (QNAP) (cross+nativ)
CPU-Target: X32 / X64 / ARMv5
Wohnort: Krefeld

Re: Synchronize(), TThread und Bibliotheken

Beitrag von mschnell »

Synchronize macht folgendes:
- sende Event an Mainthread
- versetze Thread in Wartezustand
- im Mainthread läuft irgendwas anderes
- Mainthread kommt irgendwann dazu, das Event des Threads zu bearbeiten (alle Events abgearbeitet oder "Application.ProcessMessages)
- der Mainthread arbeitet die synchronisierte Methode ab
- der Mainthread lässt den Thread weiterlaufen.

Dadurch kann es nicht zu Konflikten zwischen Mainthread und Thread bei Zugriff auf Variablen, Listen, etc. kommen.

Der Thread wartet also beliebig lange im "Synchronize"-Aufruf. Je nach Verwendung des Threads ist das nicht sinnvoll.

Eine möglicherweise besser geeignete Methode ist, einfach nur das Event ,it "PostMessage" oder "PostThreadMessage" an den MainThread zu schicken und dort mit "procedure...Message" zu empfangen. Ich glaube in "SyncOBJ" gibt es auch Unterstützung dafür.

Nachteil: Vorsicht bei Ressourcen, die von Thrfead und Mainthread gemeinsam verwendet werden !

-Michael

Targion
Beiträge: 688
Registriert: Mi 3. Okt 2007, 21:00
OS, Lazarus, FPC: Linux (L 0.9.29 FPC 2.4.2)
CPU-Target: x86_64

Re: Synchronize(), TThread und Bibliotheken

Beitrag von Targion »

Warum hängt der Thread denn dann beim Synchronize()? Im Hauptprogramm wird so lange Application.ProcessMessages gemacht, bis ein bestimmtes Signal empfangen wurde.
Der Thread läuft in der shared library, das Hauptprogramm natürlich separat.

Ist PostMessage nicht eine WindowsAPI-Funktion? (Ich nutze Linux, daher frage ich) In meiner Delphi-Zeit war es das zumindest...

marcov
Beiträge: 1104
Registriert: Di 5. Aug 2008, 09:37
OS, Lazarus, FPC: Windows ,Linux,FreeBSD,Dos (L trunk FPC trunk)
CPU-Target: 32/64,PPC(+64), ARM
Wohnort: Eindhoven (Niederlande)

Re: Synchronize(), TThread und Bibliotheken

Beitrag von marcov »

Targion hat geschrieben:Warum hängt der Thread denn dann beim Synchronize()? Im Hauptprogramm wird so lange Application.ProcessMessages gemacht, bis ein bestimmtes Signal empfangen wurde.
Der Thread läuft in der shared library, das Hauptprogramm natürlich separat.
Nein. Es gibt zwei RTLs, eine in Hauptprogramm, und eine in der shared Lib. Synchronize in shared lib nutzt RTL variabelen von der shared Lib, nicht die des Hauptprogramm.

Kurz: alles mit FPC mit shared libraries is reines Hacken, und hoffen das alles gut geht. FPC tut da nichts.

Lese mal dies: http://wiki.freepascal.org/packages" onclick="window.open(this.href);return false;
Ist PostMessage nicht eine WindowsAPI-Funktion? (Ich nutze Linux, daher frage ich) In meiner Delphi-Zeit war es das zumindest...
Ja. Und das wuerde vielleicht auch da schief gehen wenn mann das zur Haupthandle der shared lib RTL schicken werde.

Targion
Beiträge: 688
Registriert: Mi 3. Okt 2007, 21:00
OS, Lazarus, FPC: Linux (L 0.9.29 FPC 2.4.2)
CPU-Target: x86_64

Re: Synchronize(), TThread und Bibliotheken

Beitrag von Targion »

Es muss doch irgendwie möglich sein, den Thread kurzzeitig zu verlassen, einen Callback zu senden und dann weiterzumachen... Wenn das nicht geht, habe ich ein ziemliches Problem, da die lib Anfragen asynchron bearbeiten muss, damit Hauptprogramm (mit GUI) beim ausführen eines Kommandos nicht einfriert und parallel Aktionen ausgeführt werden können.

Hitman
Beiträge: 512
Registriert: Mo 25. Aug 2008, 18:17
OS, Lazarus, FPC: ArchLinux x86, WinVista x86-64, Lazarus 0.9.29, FPC 2.4.1
CPU-Target: x86
Wohnort: Chemnitz

Re: Synchronize(), TThread und Bibliotheken

Beitrag von Hitman »

Targion hat geschrieben:Es muss doch irgendwie möglich sein, den Thread kurzzeitig zu verlassen, einen Callback zu senden und dann weiterzumachen... Wenn das nicht geht, habe ich ein ziemliches Problem, da die lib Anfragen asynchron bearbeiten muss, damit Hauptprogramm (mit GUI) beim ausführen eines Kommandos nicht einfriert und parallel Aktionen ausgeführt werden können.
Warum lässt du nich die Hauptanwendung den Thread verwalten? Der Thread ruft dann die Funktion in der Library auf und beim Callback kann alles wunderbar synchronisiert werden.

Targion
Beiträge: 688
Registriert: Mi 3. Okt 2007, 21:00
OS, Lazarus, FPC: Linux (L 0.9.29 FPC 2.4.2)
CPU-Target: x86_64

Re: Synchronize(), TThread und Bibliotheken

Beitrag von Targion »

Die Lib empfängt ebenfalls asynchron Signale von diversen PackageKit-Funktionen und muss auf diese warten können.
Wenn das nicht in einem Thread passiert, empfängt das Programm diese Signale nicht, da es in der Lib keine "MessageQueue" gibt.

Was passiert, wenn ich sowas in TThread.Execute() machen würde:

Code: Alles auswählen

DoSomething;
sleep(4);
blah;
Suspend();
SendCallbackSignal('xyz');
Resume();
blub;
Würde SendCallbackSignal dann solange nicht ausgeführt werden, bis von woanders her ein Resume() gemacht wird? Oder wird die Funktion beendet und dann Suspended? Oder - was das beste wäre - wird SendCallbackSignal() dann im Mainthread ausgeführt?

Ich könnte die ganze Methode in einzelne Elemente zerhacken und die dann einzeln in einem Thread ausführen - das wäre aber ein unglaublicher Wahnsinn, da es eine ganze Reihe von extrem umfangreichen Methoden ist.

mschnell
Beiträge: 3444
Registriert: Mo 11. Sep 2006, 10:24
OS, Lazarus, FPC: svn (Window32, Linux x64, Linux ARM (QNAP) (cross+nativ)
CPU-Target: X32 / X64 / ARMv5
Wohnort: Krefeld

Re: Synchronize(), TThread und Bibliotheken

Beitrag von mschnell »

Targion hat geschrieben:Ist PostMessage nicht eine WindowsAPI-Funktion? (Ich nutze Linux, daher frage ich) In meiner Delphi-Zeit war es das zumindest...
Nö !

Der Mechanismis "Postmessage" -> "procedure...message" funktioniert prima auch in Linux. (Ich habe gerade ein Programm laufen, das das verwendet).

Die LCL implementiert den "Windows-ähnlichen" Message Transport durch eine (z.B. im GTK-Interface (aka "WidgetSet")) realisierte Event-Queue:

in Winapi.inc:

Code: Alles auswählen

function PostMessage(Handle: HWND; Msg: Cardinal; WParam: WParam; LParam: LParam): Boolean;
begin
  Result := WidgetSet.PostMessage(Handle, Msg, WParam, LParam);
end;
bei aktivem gtk-Interface realisiert in gtkwinapi.inc:

Code: Alles auswählen

function TGtkWidgetSet.PostMessage(Handle: HWND; Msg: Cardinal; wParam: WParam;
  lParam: LParam): Boolean;
...
Das nützt Dir allerdings nichts, wenn tatsächlich die shared Library ihre eigene RTL und damit auch ihre eigene Event-Queue realisiert. Dann Kann das Event im Mainthread nicht ankommen.

Es bleiben natürlich Betriebssystem-Mittel wie Sockets oder Pipes um Mitteilungen zu transportieren und Semaphoren/Mutex um einen Thread vorübergehend anzuhalten. Die Performace ist aber sicher viel schlechter als mit LCL-Mitteln der User-Space--Thread-Synchronisierung.

-Michael

Targion
Beiträge: 688
Registriert: Mi 3. Okt 2007, 21:00
OS, Lazarus, FPC: Linux (L 0.9.29 FPC 2.4.2)
CPU-Target: x86_64

Re: Synchronize(), TThread und Bibliotheken

Beitrag von Targion »

Ich habe vielleicht (nach einer Weile Nachdenken) eine Art Workaround gefunden: Die Unit MTProcs.pas implementiert einen Threadpool, um Funktionen parallel auszuführen. Dabei läuft eine Funktion im Kontext des Mainthreads weiter. Das heißt, ich könnte dort die Verarbeitung meiner Callbacks machen. Im Hauptprogramm muss das Ganze dann auch nochmal in einem Thread laufen. (wird bestimmt grausam zu debuggen)

Die lib verwendet NoGUI als Widgetset und darf von keinem WS abhängen. Die lib hat leider eine eigene RTL. Ich glaube, die Lösung mit Semaphoren wäre auch nicht unbedingt so gut....
Ich probiere noch mal ein wenig rum...

EDIT: Im Moment sieht's nicht so gut aus. Ich frage auch mal auf der FPC-Mailingliste, ob da jemand eine Idee hat.

mschnell
Beiträge: 3444
Registriert: Mo 11. Sep 2006, 10:24
OS, Lazarus, FPC: svn (Window32, Linux x64, Linux ARM (QNAP) (cross+nativ)
CPU-Target: X32 / X64 / ARMv5
Wohnort: Krefeld

Re: Synchronize(), TThread und Bibliotheken

Beitrag von mschnell »

Targion hat geschrieben:Die lib verwendet NoGUI als Widgetset und darf von keinem WS abhängen.
Die Begriffe gehen hier etwas durcheinander.
Für mich ist "Widget Set" eine durch das System an Lazarus zur Verfügung gestellte Funktionalität (z.B. GTK1, GTK2, Windows) und "Widget Type" die in Projekt-Options -> Compiler-Options getroffene Auswahl (z.B. "gtk2 (beta)" oder auch "NOGUI". Das wird in der LCL auch "Interface" genannt (dieser Begriff ist natürlich hochgradig ambivalent....).

Hier ist "NOGUI" eben der einzige Widget-Type, der zur Laufzeit keinen vom System zur Verfügung gestellten Widget-Set verlangt.

NOGUI stellt aber nicht nur keine Bindung an einen Widget-Set her (also auch keine GUI zur Verfügung), sondern realisiert auch keine Event-Queue, obwohl die Event-Queue bei "GTK" <anders als bei Windows> nicht durch durch den (System-) Widget-Set realisiert ist, sondern durch Pascal-Programmierung in der Implementierung des entsprechenden Widget-Types). "NOGUI", sollte also besser "DUMMY" heißen, weil es gar keine Funktionalität zur Verfügung stellt, sondern nur das Compilieren des Projektes ermöglicht.

Ich bin gerade dabei, einen neuen Widget-Type zu basteln, der keinen Widget-set braucht, aber eine Event-Queue zur Verfügung stellt.

Aber auch das löst Dein Problem mit der doppelten RTL nicht :(.

Was Du brauchen würdest wäre ein ein Widget-Typ "NOGUI other RTL". Das ist prinzipiell sicherlich machbar, könnte aber einigen Aufwand bedeutet. Ist vielleicht etwas einfacher, wenn mein Widget-Type "NOGUI-LInux" (o.ä.) als Beispiel fertig ist.

-Michael

marcov
Beiträge: 1104
Registriert: Di 5. Aug 2008, 09:37
OS, Lazarus, FPC: Windows ,Linux,FreeBSD,Dos (L trunk FPC trunk)
CPU-Target: 32/64,PPC(+64), ARM
Wohnort: Eindhoven (Niederlande)

Re: Synchronize(), TThread und Bibliotheken

Beitrag von marcov »

mschnell hat geschrieben:
Targion hat geschrieben:Ist PostMessage nicht eine WindowsAPI-Funktion? (Ich nutze Linux, daher frage ich) In meiner Delphi-Zeit war es das zumindest...
Nö !

Der Mechanismis "Postmessage" -> "procedure...message" funktioniert prima auch in Linux. (Ich habe gerade ein Programm laufen, das das verwendet).
Nein, es wird emuliert. Und nur fuer einfache zwecken in einfache Applikationen, Nicht im situation mit zwei runtimes, zwei LCLs usw.

marcov
Beiträge: 1104
Registriert: Di 5. Aug 2008, 09:37
OS, Lazarus, FPC: Windows ,Linux,FreeBSD,Dos (L trunk FPC trunk)
CPU-Target: 32/64,PPC(+64), ARM
Wohnort: Eindhoven (Niederlande)

Re: Synchronize(), TThread und Bibliotheken

Beitrag von marcov »

Targion hat geschrieben:Es muss doch irgendwie möglich sein, den Thread kurzzeitig zu verlassen, einen Callback zu senden und dann weiterzumachen... Wenn das nicht geht, habe ich ein ziemliches Problem, da die lib Anfragen asynchron bearbeiten muss, damit Hauptprogramm (mit GUI) beim ausführen eines Kommandos nicht einfriert und parallel Aktionen ausgeführt werden können.
Man soll der synchronize() Handler in der shared lib RTL nach dem handler in RTL 1 senden lassen. Aber das ist Expert Gebiet.

Ich wuerde shared lib meiden wenn moeglich. Fuer alles sinnvolles benoetigt mann Packages.

Alles andere ist manuel alles an einander programmieren in hoffentlich uebersichtliche Situationen, aber das ist aufwendig und gefaehrlich.

mschnell
Beiträge: 3444
Registriert: Mo 11. Sep 2006, 10:24
OS, Lazarus, FPC: svn (Window32, Linux x64, Linux ARM (QNAP) (cross+nativ)
CPU-Target: X32 / X64 / ARMv5
Wohnort: Krefeld

Re: Synchronize(), TThread und Bibliotheken

Beitrag von mschnell »

marcov hat geschrieben:Nein, es wird emuliert.
Ich sehe keinen Unterschied zwischen "emuliert" und realisiert. Du kannst es gerne "emuliert" nennen, weil die ursprüngliche Dokumentation für die Funktionalität von Microsoft stammt. (manche sagen ja auch Mono emuliert .Net :) )
marcov hat geschrieben:Und nur fuer einfache zwecken in einfache Applikationen
Mit sehr guter Performance, komplett innerhalb der LCL realisiert, verwendbar um Messages von einem Thread zum Mainthread zu schicken (wie es von Delphi-Programmierern immer schon verwendet worden ist, oft ohne dass die wussten das da eine "nackte" Windows-API verwendet wird.)
marcov hat geschrieben:Nicht im situation mit zwei runtimes, zwei LCLs usw.
Da hast Du natürlich recht. zwei Runtimes/LCLs im selben Programm Ist aber auch eine recht "komische" Situation. Natürlich geht es auch nicht zwischen zwei Programmen. Hier gibt es bei Windows die Baugleiche Methodik

SendMessage / procedure ... message;

(eben SendMessage und nicht PostMessage !!) Die zwischen Programmen arbeitet und nicht zwischen Threads desselben Programms. Das ist weder in Delphi noch in der LCL Architektur-unabhängig enkapsuliert und deshalb in Linux nicht verwendbar.

-Michael

Targion
Beiträge: 688
Registriert: Mi 3. Okt 2007, 21:00
OS, Lazarus, FPC: Linux (L 0.9.29 FPC 2.4.2)
CPU-Target: x86_64

Re: Synchronize(), TThread und Bibliotheken

Beitrag von Targion »

Abartig... Der ganze Code soll auch noch weiterhin mit C kompatibel bleiben, das heißt ich möchte C-Programme schreiben können, die diese lib verwenden.
Vielleicht findet jemand auf der FPC-Mailingliste eine Lösung (wer soll es sonst wissen?). Wenn nicht, probiere ich mal PostMessage. Drei last-exit optionen habe ich auch noch: Das DoParallell zum (richtig) funktionieren bringen, schauen, was die GLib für mich in Sachen Threading zu bieten hat, oder aber einen großen Teil der verwendeten 3rd-party API von asynchron auf synchron umstellen. (würde ich ungern machen, da die snychrone API eventuell bald eingestellt wird und diese Lösung meine GUI blockiert)
Viel Arbeit ist alles...

mschnell
Beiträge: 3444
Registriert: Mo 11. Sep 2006, 10:24
OS, Lazarus, FPC: svn (Window32, Linux x64, Linux ARM (QNAP) (cross+nativ)
CPU-Target: X32 / X64 / ARMv5
Wohnort: Krefeld

Re: Synchronize(), TThread und Bibliotheken

Beitrag von mschnell »

C ????

Was ist denn in C ? Wenn die Library in (GNU) C ist, sind wir mit der "doppelten LCL" aber komplett auf dem Holzweg. Aber eigene RTL-Funktionen bringt die so-library natürlich trotzdem mit.

Ein Kollege von mit hat gerade ein Delphi-Projekt mit PJ-SIP in Bearbeitung. PJ-SIP ist eine C-Library, die ebenfalls eigene Threads startet.

Er hat in C eine DLL gemacht, die mit der PJ-SIP Library statisch gelinkt ist. Diese DLL wird nun von Delphi aufgerufen. Da die (statische) PJ-Library auch Callbacks macht, werden diese in einem DLL-Aufruf an Funktionen im Delphi-Programm gekoppelt, die dann auf von der DLL aus aufgerufen werden.

Um diese Callbacks im Mainthread behandeln zu können wurde zunächst testweise mit "PostMessage / procedure message" gearbeitet (er hat nun aber eine nettere Funktionalität verwendet, die das MadSHI Delphi-Add-On zur Verfügung stellt, aber im Endeffekt dasselbe macht).

Klappt prima, allerdings läuft der Thread in der DLL natürlich weiter, wenn im Mainthread das Ereignis bearbeitet wird. Auf mit dem Thread gemeinsam verwendete Datenstrukturen muss also "von Hand" geachtet werden.

-Michael

Antworten