Nic Posted May 14, 2012 at 09:40 AM Share Posted May 14, 2012 at 09:40 AM Ich werfe mal in die Arena einen Entwurf (Delphi7 Prof., seit 2002) zumindest der kompletten Haupt-Klasse IPConnection, ohne die nix geht und die Komponenten BrickStepper(unvollständig) und BrickletIO4 (vollständig). Basierend auf der C#-Implementation, wurde versucht die Struktur weitgehends ähnlich umzusetzen. (Ausnahme z.B. die Delegates in C#). Hinzugefügt habe ich einige Basis-Klassen bzw. Typen oder Records, wo es sich u.U. anbietet den Code zu vereinfachen, um z.B. Redundanzen zu vermeiden. Ob das implem. threadsichere FIFO-Pattern (BlockingQueue) so zuverlässig ist wie in C# oder Java sollte als erstes begutachtet werden. Die Units lassen sich prima zu einer x32-Exe compil. und zumindest auf einem i5,Win7x64 ausführen. Ob es mit älteren bzw. jüngeren Delphi-Versionen als D7 compilierbar ist, muss geprüft werden. Es wird kein Anspruch auf Vollständigkeit erhoben noch die lehrbuchmässige Umsetzung von Delphi-Code. Das alles hat experimentellen Charakter und sollte erstmal nur von erfahrenen Delphi-Entw. in einem Code-Review gesichtet und getestet werden. Verwendung des Source-Codes also auf eigenes Risiko !entwurf.zip Quote Link to comment Share on other sites More sharing options...
AuronX Posted May 14, 2012 at 10:12 AM Share Posted May 14, 2012 at 10:12 AM Ich befürchte TryDequeue ist noch nicht korrekt gelocked (habe aber auch Probleme Delphi zu lesen ^^): while (Count = 0) do begin state := MsgWaitForMultipleObjects(1,job,false,timeout,QS_ALLINPUT); if (closing) or (timeout < Timeout_Infinite) or (state=WAIT_TIMEOUT) then begin result := false; exit; end; timeout := tick-GetTickCount; end; Ich verstehe nicht ganz wie, aber wenn ich es richtig sehe ist das der Code der wartet bis mindestens ein Eintrag in der Queue steckt (das ist jetzt eine Annahme von mir). Daraufhin kommt dieser Code: writeLock.Acquire; try p:=queue.Pop; item := p^; dispose(p); finally writeLock.Release; end; Das Problem ist, dass zwischen dem Aquire und dem Verlassen der while-schleife darüber kein locking besteht. Es ist also möglich, dass mehrere Threads die while-schleife verlassen, dann bekommt der erste Thread das writeLock (Thread 2 hängt jetzt am aquire), holt sich das einzige Item in der Queue und gibt das lock wieder ab. Jetzt kann der zweite Thread weiterlaufen, beim Pop knallt es jetzt aber. Der C#-Code funktioniert deswegen, weil die gesamte Schleife in einem locked-Bereich liegt, aber das Monitor.Wait es zulässt, dass man sein Lock mittendrin wieder abgibt und auch wiederbekommen kann. Du müsstest also sicherstellen, dass man vor dem Prüfen des count das lock aquired, und es wieder abgibt und wartet falls der count == 0. Falls der count > 0, dann sollte man das lock behalten, poppen gehen und danach das lock abgeben. Viele Grüße Jan Quote Link to comment Share on other sites More sharing options...
Nic Posted May 14, 2012 at 10:24 AM Author Share Posted May 14, 2012 at 10:24 AM Anfangs hatte ich die CriticalSection (WriteLock) zu Beginn und Ende von TryDequeue eingetragen, aber das führte dazu, dass der HauptThread, der nur dort reinläuft, das Enqueue vom Recv-Thread aber solange blockiert, bis die 2.5 sec abgelaufen sind. Das führte dazu, adss nie ein Device geadded wurde. Deshalb der Lock erst später wenn von der Queue gepoppt wird. Innerhalb der Zeitschleife wird aber auf das geblockte Count geprüft und zur Laufzeit wird dort die Count = 1 aber festgestellt. Das lock(writeLock) in C# entspricht m.W. den Acquire und Release in Delphi writeLock.Acquire; try ... finally writeLock.Release; end; Das Monitoring wird in Delphi 7 noch nicht unterstützt, mir ist allerdings noch ist ganz klar wie man das durch D7 Bordmittel alternativ lösen könnte. Aber ich schaue mir mal Deinen Ansatz heute abend genauer an. Danke fürs Code Review. Hmmh, ich sehe gerade das die Funktion Count in den C#Bindings überhaupt nicht benutzt wird, es wird immerzu das Property queue.count abgefragt, hat das ev. mit der o.g. Situation zutun ? Quote Link to comment Share on other sites More sharing options...
AuronX Posted May 14, 2012 at 11:43 AM Share Posted May 14, 2012 at 11:43 AM Hmmh, ich sehe gerade das die Funktion Count in den C#Bindings überhaupt nicht benutzt wird, es wird immerzu das Property queue.count abgefragt, hat das ev. mit der o.g. Situation zutun ? Die Funktion count macht ja nicht mehr als innerhalb einer critical-section den queue.count abzufragen. Da queue.count sonst auch nur innerhalb der locks verwendet wird ist das äquivalent. Das lock(writeLock) in C# entspricht m.W. den Acquire und Release in Delphi writeLock.Acquire; try ... finally writeLock.Release; end; Tatsächlich sieht der vom C#-Compiler generierte Code ziemlich genau so aus (abgesehen von anderen Locking-Klassen ) Anfangs hatte ich die CriticalSection (WriteLock) zu Beginn und Ende von TryDequeue eingetragen, aber das führte dazu, dass der HauptThread, der nur dort reinläuft, das Enqueue vom Recv-Thread aber solange blockiert, bis die 2.5 sec abgelaufen sind. Das klingt danach, dass du während des wartens das lock nicht abgegeben hast. Das wäre aber nötig. Ich versuche mal in Pseudo-code darzustellen wie es grob aussehen könnte (nicht schön aber selten): while(true) { lock.aquire(); if(count > 0) { break; } lock.release(); WaitSomeTime(); } pop(); lock.release(); In diesem Beispiel habe ich jetzt sowas wie closing und exception-handling mal ausgeblendet. Das ist jetzt nur exemplarisch fürs locking, wenn du sonst keine besseren Bordmittel von Delphi bekommst. Quote Link to comment Share on other sites More sharing options...
Nic Posted May 14, 2012 at 12:11 PM Author Share Posted May 14, 2012 at 12:11 PM Dann würde das etwa so aussehen: begin result := false; writeLock.Acquire; job:=CreateEvent(nil,false,false,nil); try try tick:=GetTickCount + DWord(timeout); while (true) do begin writeLock.Acquire; if (Count > 0) then break; state := MsgWaitForMultipleObjects(1,job,false,timeout,QS_ALLINPUT); writeLock.Release; if (closing) or (timeout < Timeout_Infinite) or (state=WAIT_TIMEOUT) then begin result := false; exit; end; timeout := tick-GetTickCount; end; p:=queue.Pop; item := p^; dispose(p); result := true; except on E: Exception do raise Exception.Create('TBlockingQueue.TryDequeue:' + e.Message); end finally CloseHandle(job); writeLock.Release; end; end; Was ist aber mit dem WriteLock zu Proc-Begin bzw. Ende ? Quote Link to comment Share on other sites More sharing options...
AuronX Posted May 14, 2012 at 01:46 PM Share Posted May 14, 2012 at 01:46 PM Zu der Schleife: Findet das Warten nicht in der Funktion MsgWaitForMultipleObjects statt? Weil du das lock erst danach freigibst, das heißt also während du wartest darf es sich niemand anders nehmen. Ich würde jetzt vermuten, dass das Release VOR dem MsgWaitForMultipleObjects stehen sollte. Das if(closing) usw sollte wohl lieber zwischen aquire und if(count > 0) stehen, auf jeden fall sollte es nur dort stehen wo du das lock gerade besitzt. Sonst ist es wieder möglich, dass jemand close aufruft, nachdem du auf closing geprüft hast. Quote Link to comment Share on other sites More sharing options...
Nic Posted May 14, 2012 at 02:26 PM Author Share Posted May 14, 2012 at 02:26 PM Da hast Du recht, danke für Dein Feeback ! Quote Link to comment Share on other sites More sharing options...
Nic Posted May 15, 2012 at 11:12 AM Author Share Posted May 15, 2012 at 11:12 AM @TF Gibt es auf Github ein Repository wo ich die Prototypen ev. ablegen kann ? Für ein Update von 1-2 Klassen möchte ich ungern ein neues Post mit Attachment ablegen. Quote Link to comment Share on other sites More sharing options...
AuronX Posted May 15, 2012 at 11:35 AM Share Posted May 15, 2012 at 11:35 AM Meiner Ansicht nach würde es hierher gehören: https://github.com/Tinkerforge/generators Dort Unterordner delphi und erstmal alle Klassen rein. Auch wenn es bisher nicht generiert wird ^^ Quote Link to comment Share on other sites More sharing options...
Nic Posted May 15, 2012 at 11:58 AM Author Share Posted May 15, 2012 at 11:58 AM Für den Github brauche ich einen eigenen Account ? Quote Link to comment Share on other sites More sharing options...
AuronX Posted May 15, 2012 at 12:22 PM Share Posted May 15, 2012 at 12:22 PM Github wird nicht von TF betrieben sondern ist ne unabhängige Seite die Git-Repositories für andere Leute hostet. Deswegen brauchst du da auch einen eigenen Account. Solltest du bisher nicht mit Git oder anderen Versionsverwaltungssystemen vertraut sein, kannst du dich ja auf http://help.github.com erstmal grundsätzlich damit vertraut machen. Allerdings gibt es definitiv eine gewisse Einstiegshürde, wenn man noch nie vorher Versionsverwaltung betrieben hat. Quote Link to comment Share on other sites More sharing options...
Nic Posted May 15, 2012 at 12:48 PM Author Share Posted May 15, 2012 at 12:48 PM SVN und Jira Erfahrungen. Gab es oder gibt es hier im TF-Portal jemals eine kurze Einweisung wie wir Github im Hinblick auf Mitarbeit beim Source-Code für TF-Produkte zu benutzen haben ? Sicher kann ich mir die Online-Hilfe reinziehen, aber das klärt nur die techn. Benutzung von Github, aber wie soll z.B. die Source-Code Formatierung aussehen, welche Ansprüche hat man zwecks Organisation und Handhabung der Sourcen für die TF-Produkte etc... Und wenns dann mal mehr Aufklärung gegeben hat, welchen der Account-Arten von Github habe ich zu wählen um für die TF-Gemeinde "produktiv" zu sein ? Reicht der kostenlose OpenSource Acc ? Oder sind damit Einschränkungen im TF-Repos zu rechnen ? Wäre es gar möglich zwecks guten Kundenservice die TF-Accounts gleich auch autom. bei Github anzulegen ? Sozusagen Github transparent im TF-Portal ist. Quote Link to comment Share on other sites More sharing options...
AuronX Posted May 15, 2012 at 02:54 PM Share Posted May 15, 2012 at 02:54 PM Letzteres ist technisch nciht möglich und ich vermute sogar gegen die Bedingungen von Github (automatisches Anlegen von Accounts). Zumal ja nur ein Bruchteil der Forenuser auf Github was beisteuern wird und dann noch viele schon vorher einen Account hatten (wie ich). Code-formatierungen wird es von TF wohl zu nicht-unterstützten Sprachen kaum geben. Ansonsten reicht aber ein kostenloser Account völlig aus. Grundprinzip bei allen Github-Projekten sieht so aus: Du gehst auf das öffentliche Repo, dann forkst du es und führst alle Ändeurngen an deiner eigenen Kopie durch. Wenn was dabei ist was du für teilenswert hälst, dann kannst du ne "Pull Request" stellen, das ist quasi die Bitte an TF deine Änderungen zu übernehmen. Dann kann TF sich das anschauen, villt noch mit dir Rücksprache halten und am Ende übernehmen. Das war Github in Kurzform. Falls es jetzt noch Organisatorisch was gibt kann TF das ja nachtragen, aber meiner Erfahrung nach ist es recht unkompliziert ^^ Quote Link to comment Share on other sites More sharing options...
Nic Posted May 16, 2012 at 09:43 AM Author Share Posted May 16, 2012 at 09:43 AM Danke Jan, aber das ist mir erstmal zu umständlich bei dem lauen Interesse. Aber mit dem offiziellen Delphi-Bindings ist ev. bald zu rechnen Den Anfang dazu habe ich schon mal geleistet... Quote Link to comment Share on other sites More sharing options...
AuronX Posted May 19, 2012 at 09:01 PM Share Posted May 19, 2012 at 09:01 PM Bin grad noch im Urlaub, aber wenn es nur darum geht das bisher erreichte allgemein verfügbar zu machen, dann stell es einfach ins Forum und ich sortiere es zu nem Pull Request in deinem Namen ^^ Quote Link to comment Share on other sites More sharing options...
pluto Posted June 13, 2012 at 03:18 PM Share Posted June 13, 2012 at 03:18 PM Wird hier noch weiter gearbeitet? Edit01 Auf den Ersten Blick sieht der Code Recht gut aus. Schön aufgeräumt. Müsste mit wenige Änderungen auch unter Lazarus/FPC laufen. z.b. die unit windows muss mit Compiler-Deriktiven umlammert werden. Vielleicht sollten wir versuchen, gemeinsam den Code voran zu treiben? Edit02: "ScktComp, Sockets" werden nicht gefunden. unter Lazarus 1.1 Ubuntu 12.4 Beta 2 Edit03: Ich finde kein Ersatz oder unit für "CreateEvent". Vielleicht war ich etwas zu voreilig. Quote Link to comment Share on other sites More sharing options...
pluto Posted June 13, 2012 at 03:37 PM Share Posted June 13, 2012 at 03:37 PM Ich kann es nun Komplieren. Bei einigen Stellen musste ich die Parameter Ändern. Du hattest Globale Variablen genommen, als Lokalen Variablen für Funktionen. Außerdem musste ich bei allen Event's Zuweisungen ein @ davor machen. Und die Unit Windows konnte ich teilweise durch LCLType ersetzten. wegen "Short". Nun habe ich da Probleme, womit ich gerechnet habe: Es gibt noch keine Socktet Komponenten unter Lazarus. Jedenfalls habe ich noch keine gefunden bis jetzt. edit01: fpSock gibt es.... Edit02: Ich habe auch nur das "Starter-Kit"... Daher werde ich wohl eigene Units für meine Bricks erstellen z.b. für das LCD-Brick. Quote Link to comment Share on other sites More sharing options...
Nic Posted June 14, 2012 at 09:18 AM Author Share Posted June 14, 2012 at 09:18 AM Klasse pluto und danke für dein Engagement. Welche globale Variablen waren das ? Wie war es denn mit der BlockingQueue ? Kannst Du die compilieren ? Eig. arbeite ich an den Bindings nicht mehr weiter, ich möchte photron nicht dazwischen funken, m.W. ist er an den Delphi-Binding augenblicklich dran. Könntest Du Deine Veränderungen hier mal reinstellen, ich würde den Code mal unter D7 ausprobieren. Gibt es unter FPC eine VCL, d.h. gibt es visuelle Komponenten ? Quote Link to comment Share on other sites More sharing options...
pluto Posted June 14, 2012 at 12:25 PM Share Posted June 14, 2012 at 12:25 PM Klasse pluto und danke für dein Engagement. Ich war leider etwas voreilig. Ich habe mir gedacht: ich warte einfach ab, bis es eine Delphi Anbindung gibt. Solange nutzte ich Lazarus und PHP zum "Testen". z.b. kann ich ein PHP Script erstellen, welches den LCD Steuern kann. Das wird dann von Lazarus aufgerufen. Aber ich werde gerne auf Fragen Antworten. Von Zeit, zu Zeit werde ich versuchen mich weiter mit TCP/IP unter Lazarus zu befassen. Leider habe ich kein Einstig in das Thema gefunden. Ich wollte erst mal eine Verbindung zum BrickD herstellen und einfach nur "lauschen", was da ankommt und wie die "unterhaltung" zwischen BrickV und BrickD aussieht. Welche globale Variablen waren das ? Es waren verschiedene. Meistens beim constructor. Ich weiß nicht wie Delphi das Handhabt. Wie war es denn mit der BlockingQueue ? Kannst Du die compilieren ? Leider nicht vollständig: ich musste TBlockingQueue.TryDequeue ausklammern. CreateEvent habe ich leider nicht. Eig. arbeite ich an den Bindings nicht mehr weiter, ich möchte photron nicht dazwischen funken, m.W. ist er an den Delphi-Binding augenblicklich dran. Ach so, dass wusste ich nicht. Aber, es kann ja nicht schaden,wenn er den Genarator gleich für FPC auslegt. Die Probleme sind "Minimal" und kann man gut "Auslagern", denke ich. Könntest Du Deine Veränderungen hier mal reinstellen, ich würde den Code mal unter D7 ausprobieren. Findest du im Anhang. Gibt es unter FPC eine VCL, d.h. gibt es visuelle Komponenten ? Das auch. Aber ich nutzte Lazarus. Lazarus bietet die LCL an, die Kompatibel ist zu VCL. Kompatibel heißt in diesen Sinn: Theoretisch. In der Regel klappt es. Im FPC gibt es wohl auch einige Packete, wo mit du auf GTK2 und QT und die Windows API zugreifen kannst, aber über Lazarus ist es deutlich einfacher. Ich finde dieses Baukasten System einfach Toll. Gut "Mängel" gibt es immer, aber nur kleine... aber das ist ein anders Thema. Auch das es schon für viele Programmiersprachen schon Anbindungen gibt ist Klasse. Da ist immer eine runter die man kann. Bei mir ist es PHP. Jedenfalls mehr als Java. Edit1: Den Anhang vergesen. Unter Delphi7 wirst du ihn so nicht Kompilieren können. Du hast keine LCLType und LCLInft und der gleichen. Die müssten in Compilier-Schalter entwurf_pluto.zip Quote Link to comment Share on other sites More sharing options...
borg Posted June 14, 2012 at 12:34 PM Share Posted June 14, 2012 at 12:34 PM Ich wollte erst mal eine Verbindung zum BrickD herstellen und einfach nur "lauschen", was da ankommt und wie die "unterhaltung" zwischen BrickV und BrickD aussieht. Das ist nicht möglich, so funktionieren Sockets nicht. Du kannst dir aber mit Programmen wie Wireshark angucken was auf der Verbindung passiert! Quote Link to comment Share on other sites More sharing options...
pluto Posted June 14, 2012 at 01:30 PM Share Posted June 14, 2012 at 01:30 PM Das ist nicht möglich, so funktionieren Sockets nicht. Du kannst dir aber mit Programmen wie Wireshark angucken was auf der Verbindung passiert! Danke für die Antwort. Ich dachte mir schon, dass es so nicht geht. Ich habe es mal mit telnet versucht, die Verbindung "abzuhören". Damit konnte ich nur das sehen, was BrickV mit BrickD ausgetauscht hat, und auch nur einmal beim Verbinden. Aber wie macht das denn "Wireshark"? Quote Link to comment Share on other sites More sharing options...
borg Posted June 14, 2012 at 02:26 PM Share Posted June 14, 2012 at 02:26 PM Das geht über einen Treiber im Betriebssystem der Hardwarenahen Zugriff auf die Protokolle erlaubt, nichts was man selber machen könnte . Quote Link to comment Share on other sites More sharing options...
pluto Posted June 14, 2012 at 04:14 PM Share Posted June 14, 2012 at 04:14 PM Das meine ich nicht. Linux unterstützt das ja. Die Frage geht eher: Wie geht das? Wie kann ich auf die Sockets zugreifen mit FPC/Lazarus? Mir ist klar, ich muss ein Port Öffnen und dann Lauschen. Ich lese immer wieder das man Ports wie Dateien öffnen kann. Habe ich aber noch nie geschafft. Quote Link to comment Share on other sites More sharing options...
Nic Posted June 15, 2012 at 09:05 AM Author Share Posted June 15, 2012 at 09:05 AM Sag mal willste uns veräppeln nach 10 sec Suche über Google http://wiki.freepascal.org/Sockets Ich kann mir auch nicht vorstellen, daß solche elementaren Bausteine wie Sockets in einer Programmiersprache nicht vorhanden sind...Ansonsten einfach mal googlen. Und welchen Constructor in den Delphi-Bindings meinst du, da gibt es zahlreiche... Mach mal bitte ein Codeausschnitt hier rein, wo du vermutest eine globale Var. wird benutzt. Hab mir Deine Änderungen mal angeschaut: Du meinst ev. TBaseThread, dort ist eine (private) Klassenvariable mit Namen ipconn, ebenso heißt aber auch das Argument im Klassenkonstruktor. Quote Link to comment Share on other sites More sharing options...
pluto Posted June 15, 2012 at 12:44 PM Share Posted June 15, 2012 at 12:44 PM nach 10 sec Suche über Google Ja die habe ich auch gefunden, nur gibt es keinen Code mehr dazu.Jedenfalls habe ich keinen gefunden. Ich kann mir auch nicht vorstellen, daß solche elementaren Bausteine wie Sockets in einer Programmiersprache nicht vorhanden sind...Ansonsten einfach mal googlen. Es gibt bestimmt auch was. Aber das muss ich erst finden. Ich habe ja auch schon das eine oder andere Gefunden, nur gibt es dazu keine Beispiele. Z.B. LNet oder Synapse oder halt ftsocks und sowas. Es gibt da auch im FPC-Ordner einige Sachen zu, aber ich weiß noch nicht wie man damit umgeht. Von Zeit zu Zeit werde ich aber mal weiter suchen. Das Problem ist auch:Das meiste ist leider in Englisch und das kann ich kaum. (Ich weiß ein Widerspruch an sich) Und welchen Constructor in den Delphi-Bindings meinst du, da gibt es zahlreiche... Überall wo ich ein A an den Parameter vorgeschoben habe.Aber ich kann eine Liste erstellen. Hab mir Deine Änderungen mal angeschaut: Du meinst ev. TBaseThread, dort ist eine (private) Klassenvariable mit Namen ipconn, ebenso heißt aber auch das Argument im Klassenkonstruktor. Z.B. Damit kommt FPC nicht zurecht, jedenfalls höchsten nur im Delphi-Modus. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.