amiga-news ENGLISH VERSION
.
Links| Forum| Kommentare| News melden
.
Chat| Umfragen| Newsticker| Archiv
.

amiga-news.de Forum > Programmierung > Fragen zu Intuition-Messages [ - Suche - Neue Beiträge - Registrieren - Login - ]

-1- 2 [ - Beitrag schreiben - ]

07.07.2006, 08:50 Uhr

Reth
Posts: 1858
Nutzer
Hallo allerseits,

habe mal ein paar Frage an die Experten:

Gibt es unterschiedliche Möglichkeiten, Intuition-Messages eines Fensters abzufragen?

Habe unter folgendem Link:

Tutorial

2 Möglichkeiten gesehen: Eine bei dem Bsp. Close Window, eine bei dem Bsp. Simple Menu.

Die erstere scheint mir ein busy-waiting zu sein, wobei dort keine Blockierung entsteht und man immer seine Runden in der Schleife dreht, bis was passiert.

Bei zweiterer Möglichkeit hat man mit wait() doch wohl ein blockierendes warten, solange, bis ein Signal eintrifft, oder?

Meine nächste Frage richtet sich auf die Wartefunktion. Ich habe mal in einem Amiga-Bsp.-Source gesehen, dass eine Funktion gerufen wurde, die so ähnlich aussah wie:

Wait_For_Signal(window);

Da die in dem Bsp. nirgends auftauchte, dachte ich, dass es sich hier um eine Funktion des AOS handelt, ists wohl aber nicht, oder?
Leider finde ich das entsprechende Bsp. nicht mehr.

Und die 3. Frage lautet: Wie sinnvoll ist es, Messages, v.a. IntuiMessages zu kopieren, um sie z.B. in C++ Klassen zu wrappen und vor der Weiterverarbeitung dieser C++ Objkete einen reply zu machen?

Vielen Dank schon einmal
Ciao

[ - Antworten - Zitieren - Direktlink - ]

07.07.2006, 10:03 Uhr

thomas
Posts: 7716
Nutzer

Das erste Beispiel ist in der Tat ein Busy-Loop und das ist in einem Multitasking-System absolut verboten. Wer das Programmiert hat, sollte erschossen werden.

Wait() wartet natürlich bis eins der Ereignisse eintritt, auf die gewartet wird. Wie soll das sonst gehen ? Was verstehst du unter einem nich-blockierenden Warten ?

Zu Wait_For_Signal kann man nur sagen, es gibt keine OS-Funktionen mit Unterstrichen im Namen.

Zu C++ kann ich nichts sagen. Das mit den Messages sollte doch klar sein. Wenn du die Message abholst, kannst du drauf zugreifen, wenn du sie beantwortest, ist sie weg. Wenn du nach der Antwort noch auf die Daten zugreifen möchtest, mußt du sie vor dem Antworten kopieren.

Gruß Thomas

--
Email: thomas-rapp@web.de
Home: thomas-rapp.homepage.t-online.de/

[ - Antworten - Zitieren - Direktlink - ]

07.07.2006, 10:30 Uhr

Reth
Posts: 1858
Nutzer
@thomas:

Danke.

Unter nicht blockierendem Warten verstehe ich so ne Art Call-Back Mechanismus, bei dem Komponenten beim Eintreten von Ereignissen informiert werden (á la Java Events und Listener). Die Anwendung muss währenddessen nirgends blockiert werden.

In diesen Fällen ist das blockierende Warten entweder gar nicht vorhanden oder im darunterliegenden System/Framework versteckt.

(Bei Java weiss ich nicht, wie das innerhalb der JVM funktioniert, allerdings kann dort nicht in dem Sinne blockierend gewartet werden, dass die darüberliegende Anwendung nichts mehr ausführen kann. Evtl. wird dafür ein eigener Thread verwendet.)

[ - Antworten - Zitieren - Direktlink - ]

07.07.2006, 13:29 Uhr

Holger
Posts: 8116
Nutzer
Zitat:
Original von Reth:
In diesen Fällen ist das blockierende Warten entweder gar nicht vorhanden oder im darunterliegenden System/Framework versteckt.

Es ist nur versteckt.
Zitat:
(Bei Java weiss ich nicht, wie das innerhalb der JVM funktioniert, allerdings kann dort nicht in dem Sinne blockierend gewartet werden, dass die darüberliegende Anwendung nichts mehr ausführen kann. Evtl. wird dafür ein eigener Thread verwendet.)
Doch, es ist exakt so: es gibt einen Event-Handling Thread, und solange keine neuen Events anliegen, ist dieser Thread blockiert.

Anwendungen werden mit dem main-Thread gestartet und wenn kein GUI verwendet wird, enden sie auch mit diesem. Aber 99% aller Java-Anwendungen benutzen den main-Thread nur zur Initialisierung und laufen dann fast ausschließlich im Event-Handling Thread.

Und ein beliebter Fehler von Java-Programmierern ist es, lange dauernde Aktionen innerhalb eines Event-Handlers durchzuführen, womit der Handling Thread nicht mehr auf neue Messages reagieren kann, womit dann nicht mal mehr das Neuzeichnen der UI stattfindet.

Korrekt wäre es, dafür dann einen neuen Thread zu starten. Ist exakt genauso wie bei Amiga Programmen.

mfg

PS: Tut mir leid, daß ich auf die letzten Mails nicht geantwortet habe. Ich kann leider vom Büro aus nicht auf die Mails zugreifen, wenn ich sie einmal von zu Hause aus abgerufen habe.

PPS: Schick doch mal die souren, wie angekündigt...

[ - Antworten - Zitieren - Direktlink - ]

07.07.2006, 14:15 Uhr

Reth
Posts: 1858
Nutzer
Hi Holger,

Zitat:
Original von Holger:
Doch, es ist exakt so: es gibt einen Event-Handling Thread, und solange keine neuen Events anliegen, ist dieser Thread blockiert.

Anwendungen werden mit dem main-Thread gestartet und wenn kein GUI verwendet wird, enden sie auch mit diesem. Aber 99% aller Java-Anwendungen benutzen den main-Thread nur zur Initialisierung und laufen dann fast ausschließlich im Event-Handling Thread.

Und ein beliebter Fehler von Java-Programmierern ist es, lange dauernde Aktionen innerhalb eines Event-Handlers durchzuführen, womit der Handling Thread nicht mehr auf neue Messages reagieren kann, womit dann nicht mal mehr das Neuzeichnen der UI stattfindet.

Korrekt wäre es, dafür dann einen neuen Thread zu starten. Ist exakt genauso wie bei Amiga Programmen.


Aber sehe ich das richtig, dass ich in Java meine GUI aufbauen kann, die Elemente mit Listenern versehen, die auf Eingaben reagieren, aber solange keine Eingaben kommen, kann ich ausserhalb meiner Listener weiterhin Code ausführen (z.B. permanent Infos rausschreiben etc.), wobei die Listener bei Auftreten von Ereignissen ihre Behandlungsroutinen dennoch ausführen?!

Zitat:
PS: Tut mir leid, daß ich auf die letzten Mails nicht geantwortet habe. Ich kann leider vom Büro aus nicht auf die Mails zugreifen, wenn ich sie einmal von zu Hause aus abgerufen habe.

Kein Problem!

Zitat:
PPS: Schick doch mal die souren, wie angekündigt...

Sobald ich den Rest mit Handlern + Messages zusammenhabe, so dass es erstmal tut.

Ciao

[ - Antworten - Zitieren - Direktlink - ]

07.07.2006, 14:45 Uhr

whose
Posts: 2156
Nutzer
Zitat:
Original von Reth:
Hi Holger,

Zitat:
Original von Holger:
Doch, es ist exakt so: es gibt einen Event-Handling Thread, und solange keine neuen Events anliegen, ist dieser Thread blockiert.

Anwendungen werden mit dem main-Thread gestartet und wenn kein GUI verwendet wird, enden sie auch mit diesem. Aber 99% aller Java-Anwendungen benutzen den main-Thread nur zur Initialisierung und laufen dann fast ausschließlich im Event-Handling Thread.

Und ein beliebter Fehler von Java-Programmierern ist es, lange dauernde Aktionen innerhalb eines Event-Handlers durchzuführen, womit der Handling Thread nicht mehr auf neue Messages reagieren kann, womit dann nicht mal mehr das Neuzeichnen der UI stattfindet.

Korrekt wäre es, dafür dann einen neuen Thread zu starten. Ist exakt genauso wie bei Amiga Programmen.


Aber sehe ich das richtig, dass ich in Java meine GUI aufbauen kann, die Elemente mit Listenern versehen, die auf Eingaben reagieren, aber solange keine Eingaben kommen, kann ich ausserhalb meiner Listener weiterhin Code ausführen (z.B. permanent Infos rausschreiben etc.), wobei die Listener bei Auftreten von Ereignissen ihre Behandlungsroutinen dennoch ausführen?!


Ähnliche Späße kannst Du auch mit einem separaten GUI-Task (bzw. separatem Berechnungs/Ausgabe/Was-weiß-ich-Task) machen. Ich habe mich weder mit Java noch mit Threading ausführlich beschäftigt (das Task-Konzept war für meine Zwecke bisher immer mehr als ausreichend), aber ich denke mal, daß ein eigener Task für länger dauernde Verarbeitung irgendwelcher Daten und das Warten auf das Signal dieses Tasks im GUI- bzw. Main-Task für Deine Zwecke passen müßte.

Geht vermutlich nur nicht ganz so komfortabel wie das Java-Thread-Konzept (beim AmigaOS mußt Du u.A. dafür sorgen, daß das Beenden der einzelnen Tasks "sauber" erledigt wird, also z.B. Warten, daß der Berechnungstask sein Ende kundtut, bevor von diesem Task mitgenutzte Resourcen freigegeben werden, Du benötigst einen zusätzlichen Messageport für die Signale des Berechnungstasks usw.).

Grüße

--
---

:boing: µA1 PPC 750GX-800
:boing: A4000 PPC 604e-233

[ - Antworten - Zitieren - Direktlink - ]

07.07.2006, 15:17 Uhr

Holger
Posts: 8116
Nutzer
Zitat:
Original von Reth:
Aber sehe ich das richtig, dass ich in Java meine GUI aufbauen kann, die Elemente mit Listenern versehen, die auf Eingaben reagieren, aber solange keine Eingaben kommen, kann ich ausserhalb meiner Listener weiterhin Code ausführen (z.B. permanent Infos rausschreiben etc.), wobei die Listener bei Auftreten von Ereignissen ihre Behandlungsroutinen dennoch ausführen?!


Das kannst Du nur, wenn Du a) die Initialisierung aus dem main-Thread heraus durchführst und diesen nach der Initialisierung weiterverwendest oder b) explizit einen neuen eigenen Thread startest.

Wie whose schon sagte, kannst Du das unter AmigaOS genauso machen, wobei Du einiges mehr von Hand machen mußt als bei Java. Dafür ist die Wahrscheinlichkeit größer, daß Du Dir bewußt wirst, was da passiert und wann Du die Threads synchronisieren mußt.

Deine Postings zeigen ja, daß Dir auch nicht 100%ig klar ist, was da bei Java genau passiert. Und z.B. Swing mag es überhaupt nicht, wenn man aus einem anderen Thread heraus Manipulationen am GUI ohne korrekte Synchronisation durchführt...

mfg
--
Good coders do not comment. What was hard to write should be hard to read too.

[ - Antworten - Zitieren - Direktlink - ]

07.07.2006, 15:28 Uhr

Holger
Posts: 8116
Nutzer
Zitat:
Original von whose:
... Du benötigst einen zusätzlichen Messageport für die Signale des Berechnungstasks usw.).


Für Signale braucht man natürlich nur Signale, keinen ganzen MessagePort. Den braucht man, wenn man Messages austauschen will. Klingt vielleicht auf den ersten Blick nach Haarspalterei, bedeutet aber einen gewaltigen Unterschied, weil Tasks über Messages kommunizieren zu lassen innerhalb eines geschlossenen Programms ein ziemlicher Overkill sein kann.

Da reicht u.U. eine per Semaphore geschützt globale Variable vollkommen aus.

Bestes Beispiel wäre die in einem anderen Thread diskutierte Aktualisierung von GUI-Elementen über Intui-Ticks bei der Signale des Hintergrundtasks gar nicht nötig sind.

mfg
--
Good coders do not comment. What was hard to write should be hard to read too.

[ - Antworten - Zitieren - Direktlink - ]

07.07.2006, 18:12 Uhr

whose
Posts: 2156
Nutzer
Zitat:
Original von Holger:
Zitat:
Original von whose:
... Du benötigst einen zusätzlichen Messageport für die Signale des Berechnungstasks usw.).


Für Signale braucht man natürlich nur Signale, keinen ganzen MessagePort. Den braucht man, wenn man Messages austauschen will. Klingt vielleicht auf den ersten Blick nach Haarspalterei, bedeutet aber einen gewaltigen Unterschied, weil Tasks über Messages kommunizieren zu lassen innerhalb eines geschlossenen Programms ein ziemlicher Overkill sein kann.

Da reicht u.U. eine per Semaphore geschützt globale Variable vollkommen aus.
...


Da hast Du natürlich Recht. Ich wollte Reth nur an wenigen Beispielen aufzeigen, was für zusätzliche Arbeit auf ihn warten kann. Ich weiß ja nicht genau, was er vorhat. Wenn ein gemeinsam genutzter (und per Semaphore zugriffskontrollierter) Speicherbereich ausreichend ist, benötigt man natürlich keinen Messageport bzw. Inter-Task-Kommunikation per Message. Das vereinfacht die Geschichte dann doch um einiges :D

Grüße

--
---

:boing: µA1 PPC 750GX-800
:boing: A4000 PPC 604e-233

[ - Antworten - Zitieren - Direktlink - ]

07.07.2006, 20:19 Uhr

Mad_Dog
Posts: 1944
Nutzer
Zitat:
Original von Reth:

Unter nicht blockierendem Warten verstehe ich so ne Art Call-Back Mechanismus, bei dem Komponenten beim Eintreten von Ereignissen informiert werden (á la Java Events und Listener). Die Anwendung muss währenddessen nirgends blockiert werden.


Bei Multitasking-Systemen läuft das so:

Ein Task kann Ready, Running, Waiting oder Suspendet sein - das sind die Zustände des zugehörigen Automaten (Stichwort: Automatentheorie).

Wenn jetzt ein Amiga Programm mittels WaitPort() darauf wartet, daß eine Message oder per Wait() ein Signal an dem Port ankommt, ist der Task in der Zwischenzeit im Zustand Waiting. D.h. der Scheduler sorgt dafür, daß der Task schläft und keine Rechenzeit verbrät.

--
http://www.norman-interactive.com

[ - Antworten - Zitieren - Direktlink - ]

07.07.2006, 21:18 Uhr

Reth
Posts: 1858
Nutzer
@Mad_Dog:

Das schon.
Bei Java ist es aber so, dass Du Deine GUI erstellst, den entsprechenden Componenten Listener verpasst, die dann aktiv werden, wenn diese Komponente ein Event erhält. Dein ganzes Programm versetzt Du niemals selbst mittels wait() o.dgl. in den waiting-Zustand (intern wird natürlich schon gewartet s.o.).

@Holger:

Ich meinte auch nicht, dass ich aus meinem Main-Thread heraus die GUI ändern will (also Swing ins Handwerk pfuschen), aber ich dachte an Folgendes:

Z.B. in der Main-Methode die GUI erstellen, nen Knopf mit nem Listener dran, der bei Knopfbetätigung ne Ausgabe macht (System.out.println).

Die Componenten anzeigen lassen.

Danach im Hauptprogramm ne Schleife, die unentwegt System.out.println macht, bis der Knopf z.B. 10 Mal gedrückt wurde.

Habs nicht selber probiert, sollte aber tun.
Ergo: Dein Hauptprogramm arbeitet, Deine GUI empfängt dennoch Events und kann diese verarbeiten.
(Klar im Inneren wartet ein Thread auf die GUI-Ereignisse und ist im Stauts waiting, aber für den Anwendungsentwickler und -bediener stellt sich das halt anders dar!)

Ciao

[ - Antworten - Zitieren - Direktlink - ]

08.07.2006, 00:01 Uhr

DariusBrewka
Posts: 899
[Benutzer gesperrt]
Zitat:
Original von Reth:
Unter nicht blockierendem Warten verstehe ich so ne Art Call-Back Mechanismus, bei dem Komponenten beim Eintreten von Ereignissen informiert werden (á la Java Events und Listener). Die Anwendung muss währenddessen nirgends blockiert werden.


Das ist doch genau was du z.B. mit MUI machen kannst indem du z.B. für Ereignisse Callbackhooks definierst, ich denke das dürfte mit Reaction&Co auch funktionieren, dort ist es i.A. nicht gut angesehen einen Loop zu machen und dann nach if ... then manier zu handeln.


[ - Antworten - Zitieren - Direktlink - ]

08.07.2006, 00:12 Uhr

DariusBrewka
Posts: 899
[Benutzer gesperrt]
Zitat:
Original von Reth:
Und die 3. Frage lautet: Wie sinnvoll ist es, Messages, v.a. IntuiMessages zu kopieren, um sie z.B. in C++ Klassen zu wrappen und vor der Weiterverarbeitung dieser C++ Objkete einen reply zu machen?


Ich kann da keine Allgemeine Aussage machen, es kommt ausf die Message an. Normalerweise sollte es genau nach diesem Schema gehen:

1. GetMsg();
2. nötige Werte kopieren
3. ReplyMsg();
4. bearbeitung der Message

nimm aber jetzt z.B. einen ScreenNotify Mechanismus mit obigen Schema, nach ReplyMsg() wird dem System gesagt dass es jetzt den Screen schliessen kann, aber das Fenster wird erst in 4. geschlossen.

Eigentlich sagt das ReplyMsg() dass die Message bearbeitet wurde, wenn du z.B. ein Tool machst was Programme startet ist es i.A. egal ob's vorher oder später geschieht. Also ein Implizites ReplyMsg() ist nicht immer sinnvoll.


[ - Antworten - Zitieren - Direktlink - ]

08.07.2006, 00:20 Uhr

DariusBrewka
Posts: 899
[Benutzer gesperrt]
Zitat:
Original von thomas:
Das erste Beispiel ist in der Tat ein Busy-Loop und das ist in einem Multitasking-System absolut verboten. Wer das Programmiert hat, sollte erschossen werden.


so ganz stimmt das nicht denn es gibt durchaus Situationen in denen dir nichts anderes übrig bleibt. Nimm z.B. ein Programm um Bilder zu rendern mit der Möglichkeit diesen Vorgang abzubrechen, da kannst du nur einen Busy-Loop nutzen. Man kann natürlich auch einen Thread erstellen und dann ein RemTask() machen aber so toll ist das auch nicht insbesondere wenn der Task Initialisierungen vornimmt.

[ - Antworten - Zitieren - Direktlink - ]

08.07.2006, 12:42 Uhr

Holger
Posts: 8116
Nutzer
Zitat:
Original von Reth:
Ergo: Dein Hauptprogramm arbeitet, Deine GUI empfängt dennoch Events und kann diese verarbeiten.
(Klar im Inneren wartet ein Thread auf die GUI-Ereignisse und ist im Stauts waiting, aber für den Anwendungsentwickler und -bediener stellt sich das halt anders dar!)


Es stellt sich nicht anders dar. Das "Hauptprogramm" läuft in diesem Fall im main-Thread und das GUI wird im Event-Handler Thread ausgeführt. Und diese Feinheit MUSS der Programmierer kennen, eben z.B. wissen, daß er keine GUI-Änderungen aus dem main-Thread ohne Synchronisation ausführen darf.

Unter AmigaOS ist das eigentlich ähnlich, intuition zeichnet Gadgets und Fensterrahmen innerhalb des input-handlers, also im task des input.device neu und ruft auch die call-backs der BOOPSI-Objekte aus diesem heraus auf. Die Anwendung erhält nur zusätzlich Benachrichtigungen, um darüber hinaus noch Aktionen auszuführen. Und weil es nur einen input.task im ganzen System gibt, ist es besonders gefährlich, zuviele Dinge innerhalb eines solchen call-backs durchzuführen.

Da gibt es auch unterschiedliche Auffassungen, wo man die Trennlinie ziehen sollte, MUI zieht sie z.B. anders als ReAction...

Anwendungsseitig kann man natürlich trotzdem noch einen weiteren Task für das Scheduling der Gui-Events anlegen, um den Haupttask frei zu halten. Halte ich persönlich aber nicht für sinnvoll. Wenn man wiederverwendbaren GUI-code schreiben will, sollte man das Erzeugen eines neuen Tasks für die Hintergrundberechnung starten, wenn eine gebraucht wird, nicht umgekehrt...

mfg
--
Good coders do not comment. What was hard to write should be hard to read too.

[ - Antworten - Zitieren - Direktlink - ]

08.07.2006, 12:52 Uhr

Holger
Posts: 8116
Nutzer
Zitat:
Original von DariusBrewka:
Zitat:
Original von Reth:
Und die 3. Frage lautet: Wie sinnvoll ist es, Messages, v.a. IntuiMessages zu kopieren, um sie z.B. in C++ Klassen zu wrappen und vor der Weiterverarbeitung dieser C++ Objkete einen reply zu machen?


Ich kann da keine Allgemeine Aussage machen, es kommt ausf die Message an. Normalerweise sollte es genau nach diesem Schema gehen:

1. GetMsg();
2. nötige Werte kopieren
3. ReplyMsg();
4. bearbeitung der Message

nimm aber jetzt z.B. einen ScreenNotify Mechanismus mit obigen Schema, nach ReplyMsg() wird dem System gesagt dass es jetzt den Screen schliessen kann, aber das Fenster wird erst in 4. geschlossen.


Das hatten wir doch hier schon mal. ScreenNotify ist insofern ein schlechtes Beispiel, weil es das zumind. unter OS3.x bei IDCMP nicht gibt. Aber menu- und size-verify dürfen natürlich erst nach der Bearbeitung zurückgeschickt werden. Und die Frage wann/wieviel ticks gesendet werden hängt auch von Zeitpunkt des Zurückschickens ab.

Aber eigentlich sollte es eh egal sein, weil man in dieser Abfolge nichts tun sollte, das lange (im Sinne eines Computers) dauert. Alle längeren Operationen sollten eh in einem eigenen Task durchgeführt werden. Ich weiß, macht kaum jemand korrekt.

mfg
--
Good coders do not comment. What was hard to write should be hard to read too.

[ - Antworten - Zitieren - Direktlink - ]

08.07.2006, 12:57 Uhr

Holger
Posts: 8116
Nutzer
Zitat:
Original von DariusBrewka:
so ganz stimmt das nicht denn es gibt durchaus Situationen in denen dir nichts anderes übrig bleibt. Nimm z.B. ein Programm um Bilder zu rendern mit der Möglichkeit diesen Vorgang abzubrechen, da kannst du nur einen Busy-Loop nutzen.


Als Busy-Loop bezeichnet man eigentlich nur Programme, die CPU-Resourcen verschwenden, um zu warten. Programme, die mit der CPU-Zeit sinnvolle Dinge anstellen, wie z.B. rendern, gehören nicht dazu.

Trotzdem wäre es sauberer, wenn nicht der Rendering-Task auf Close-Events überprüft, sondern nur auf ein eigens dafür reserviertes Signal. Dafür sollte er auch mit Pri -1 laufen und ein Task mit normaler Priorität auf Abbruch-Trigger (Close, Esc-Key, Ctrl-C) warten und das Abbruch Signal für den Hintergrund-Task senden.

mfg
--
Good coders do not comment. What was hard to write should be hard to read too.

[ - Antworten - Zitieren - Direktlink - ]

09.07.2006, 00:51 Uhr

NoImag
Posts: 1050
Nutzer
Zitat:
Original von Holger:
Alle längeren Operationen sollten eh in einem eigenen Task durchgeführt werden.


Was ist da der Vorteil?

Zitat:
Trotzdem wäre es sauberer, wenn nicht der Rendering-Task auf Close-Events überprüft, sondern nur auf ein eigens dafür reserviertes Signal. Dafür sollte er auch mit Pri -1 laufen und ein Task mit normaler Priorität auf Abbruch-Trigger (Close, Esc-Key, Ctrl-C) warten und das Abbruch Signal für den Hintergrund-Task senden.

Macht dies die Sache nicht unnötig kompliziert? Signalabfrage in 2 Tasks statt in einem.

Tschüß




[ - Antworten - Zitieren - Direktlink - ]

10.07.2006, 16:48 Uhr

Holger
Posts: 8116
Nutzer
Zitat:
Original von NoImag:
Was ist da der Vorteil?

Daß man so etwas im Jahre 2006 noch sagen muß...
Daß das User-Interface immer noch auf den User reagiert, natürlich. Von einfachen Dingen, wie Neuzeichnen, wenn Fenster verschoben oder nach vorne geholt werden, was je nach Toolkit nicht von selbst geschieht, siehe MUI, bis hin zur Option eines Abbruch. Kennt doch jeder von älteren YAM-Versionen, die zwar einen "Abbrechen"-Button während des Mail-Downloads angeboten haben, nur dummerweise auf einen Button-Druck nicht reagiert haben, weil sie ja mit dem Download beschäftigt waren...

Zitat:
Macht dies die Sache nicht unnötig kompliziert? Signalabfrage in 2 Tasks statt in einem.

Jeden Task für sich macht es einfacher. Ein Hintergrund-Task, der von jeglichen GUI-Code freigehalten wird und ein GUI-Task, der nichts über die Art des Hintergrund-Tasks wissen muß.

Sobald Du eine neue Option ins Gui-einbaust, z.B. Abbruch über Esc, zusätzlich zum Button, oder einen PullDown-Menüpunkt stattdessen, etc., wirst Du es zu schätzen wissen.

Sobald Du eine zusätzliche Funktionalität, bzw. einen weiteren Hintergrund-Task einführst, wirst Du es zu schätzen wissen, daß das GUI lediglich ein weiteres Signal verschicken muß, statt komplett umgeschreiben zu werden...

Man hätte das AmigaOS auch als eine einzige große Library anlegen können. Das wäre schon von der Struktur einfacher gewesen und das "komplizierte" Öffnen der Bibliotheken wäre weggefallen.

Aber einfacher ist nicht besser und was als Gesamtheit ein komplexes System ist, gewinnt durch die Einfachheit der Module im Einzelnen. Nicht anders als bei der objektorientierten Programmierung, ein mittels oop entwickeltes Programm ist in seiner Gesamtheit genauso komplex, wie ein mittels assembler geschriebenes -- es erfüllt ja auch die gleiche Aufgabe. Nur die Unterteilung in jede für sich einzeln gut wartbare Klassen macht den Unterschied. (und manche Gesamtkomplexität überhaupt erst beherrschbar)

mfg
--
Good coders do not comment. What was hard to write should be hard to read too.

[ - Antworten - Zitieren - Direktlink - ]

10.07.2006, 23:27 Uhr

NoImag
Posts: 1050
Nutzer
Zitat:
Original von Holger:
Daß man so etwas im Jahre 2006 noch sagen muß...


Danke für die Blumen.

Zitat:
Daß das User-Interface immer noch auf den User reagiert, natürlich.

Deine Aussage war absolut. Nicht bei jeder längeren Aktion kann der User sinnvoll im selben Programm weiterarbeiten und um auf Abbruch zu reagieren, ist kein extra Task notwendig. Ok, du meinst das Programm kann bei Verwendung verschiedener Tasks leichter gewartet werden.

Zur Verwendung von Simple-Refresh-Fenstern schreibe ich jetzt lieber nichts.

Zitat:
Jeden Task für sich macht es einfacher. Ein Hintergrund-Task, der von jeglichen GUI-Code freigehalten wird und ein GUI-Task, der nichts über die Art des Hintergrund-Tasks wissen muß.

Grundsätzlich leuchtet dies ein, aber wenn der Hintergrundtask eine Rückmeldung vom User benötigt, dann handelt man sich eine umfangreiche Kommunikation zwischen den Tasks ein.

Zitat:
Sobald Du eine neue Option ins Gui-einbaust, z.B. Abbruch über Esc, zusätzlich zum Button, oder einen PullDown-Menüpunkt stattdessen, etc., wirst Du es zu schätzen wissen.

Hmm. Bei dem was mir da gerade so in den Sinn kommt, sehe ich keine Vereinfachung. Einfach die bereits vorhandene Funktion an anderer Stelle in der GUI-Auswertung aufrufen.

Zitat:
Sobald Du eine zusätzliche Funktionalität, bzw. einen weiteren Hintergrund-Task einführst, wirst Du es zu schätzen wissen, daß das GUI lediglich ein weiteres Signal verschicken muß, statt komplett umgeschreiben zu werden...

Auch das ist mir noch nicht passiert, die GUI komplett umschreiben zu müssen, wenn ich eine neue Funktionalität einbaue. Neuen Menüpunkt oder neuen Button in die GUI aufnehmen, von dort neue Funktion aufrufen, fertig.

Zitat:
Aber einfacher ist nicht besser und was als Gesamtheit ein komplexes System ist, gewinnt durch die Einfachheit der Module im Einzelnen. Nicht anders als bei der objektorientierten Programmierung, ein mittels oop entwickeltes Programm ist in seiner Gesamtheit genauso komplex, wie ein mittels assembler geschriebenes -- es erfüllt ja auch die gleiche Aufgabe. Nur die Unterteilung in jede für sich einzeln gut wartbare Klassen macht den Unterschied. (und manche Gesamtkomplexität überhaupt erst beherrschbar)

Naja. Ich werde mir das nochmal durch den Kopf gehen lassen, ob sich bei meinem Projekt dadurch doch die Wartung vereinfacht. Momentan sehe ich es aber nicht, auch wenn sich das in der Theorie gut anhört.

Tschüß




[ - Antworten - Zitieren - Direktlink - ]

11.07.2006, 00:18 Uhr

Holger
Posts: 8116
Nutzer
Zitat:
Original von NoImag:
Deine Aussage war absolut. Nicht bei jeder längeren Aktion kann der User sinnvoll im selben Programm weiterarbeiten und um auf Abbruch zu reagieren, ist kein extra Task notwendig. Ok, du meinst das Programm kann bei Verwendung verschiedener Tasks leichter gewartet werden.

Ich denke, das man diese Aussage exakt so absolut auch in den Autodocs von old Commodore wiederfindet. Und in jeder anderen Toolkit-Dokumentation auf jedem anderem System.

Und wenn Du nicht für alles, was die Amiga-Libs Dir so anbieten, asynchrone Varianten nachprogrammieren willst, wie z.B. für die blockierenden DOS-Funktionen, ist das mit dem Abbruch nicht so trivial.

Merke: der User will vor allem dann gerne abbrechen, wenn die I/O-Operation nicht antwortet...
Zitat:
Zur Verwendung von Simple-Refresh-Fenstern schreibe ich jetzt lieber nichts.
Besser ist es. Weil Resourcen für die Faulheit des Programmiers zu verschwenden, gerade auf dem Amiga verpönt ist. Und auf Grafikkarten machen Smart-Refresh-Fenster, aufgrund der Notwendigkeit eines rückgerichteten Datentransfers, den Bus besonders lange dicht...

Abgesehen davon ist das Vollaufen eines MessagePorts mit diversen Nachrichten auch nicht toll. Nun ja, man kann natürlich vor der Aktion erst mal IDCMP-Messages abbestellen, GUI locken, aber einfacher ist es dann auch nicht mehr.
Zitat:
Grundsätzlich leuchtet dies ein, aber wenn der Hintergrundtask eine Rückmeldung vom User benötigt, dann handelt man sich eine umfangreiche Kommunikation zwischen den Tasks ein.
Nicht umfangreicher als GUI-Code innerhalb einer Background-Aktion. Ich finde, z.B. innerhalb von DOS-Aufrufen hat GUI-Code nichts zu suchen.

Und ich gehe eigentlich immer von User-Aktion->Event->Programmaktion aus. Das ist für mich der "Amiga-Weg".
Hintergrundtask->Rückmeldung erfragen->User zu Aktion zwingen ist eher der "MsDOS-Weg".

Zitat:
Auch das ist mir noch nicht passiert, die GUI komplett umschreiben zu müssen, wenn ich eine neue Funktionalität einbaue. Neuen Menüpunkt oder neuen Button in die GUI aufnehmen, von dort neue Funktion aufrufen, fertig.
Na ja, Du scheinst sehr einfach gestrickte Programme im Hinterkopf zu haben.
Für mich reicht schon, "Datei speichern" -> Im Editor Weiterarbeiten, auch wenn die Datei auf einem langsamen Laufwerk (z.B. Netzwerk) liegt, als Beispiel.

Zitat:
Naja. Ich werde mir das nochmal durch den Kopf gehen lassen, ob sich bei meinem Projekt dadurch doch die Wartung vereinfacht. Momentan sehe ich es aber nicht, auch wenn sich das in der Theorie gut anhört.
Nicht alles liefert instantan eine spürbare Verbesserung...

mfg
--
Good coders do not comment. What was hard to write should be hard to read too.

[ - Antworten - Zitieren - Direktlink - ]

11.07.2006, 00:48 Uhr

Holger
Posts: 8116
Nutzer
@NoImag:
Nicht, daß wir aneinander vorbeireden. Die Faustregel lautet ja sinngem. das Event-Scheduling sollte nicht durch längere Aktionen blockiert werden, nicht etwa, man müsse um jeden Preis Multithreaded programmieren.

Also evtl. machst Du ja alles richtig, in dem Du vor der längeren Aktion alle UI-Elemente deaktivierst, die jetzt nicht mehr möglich sind, evtl. die IDCMP-Maske anpaßt und während die "Hintergrund"aktion (also längere Vordergrundaktion) läuft, regelmäßig auf Abbruchtrigger überprüfst (und garantieren kannst, daß die Aktion nicht indirekt blockierend auf ein anderes Ereignis wie z.B. beim DOS warten kann).

Hintergrund der absoluten Aussage ist die übliche Praxis eines Event-Handling Loops, bei dem die Abfolge "Nachricht holen"->Verarbeiten->Beantworten->"wieder von vorn" auch für länger dauernde Aktionen nicht verändert wird. Viele Programmierer denken ja noch nicht einmal darüber nach, was eine längere Aktion sein könnte.

Extrembeispiel wäre SFSSalv, bei dem man noch nicht einmal erkennen kann, ob es jetzt arbeitet oder abgestürzt ist, weil man immer noch munter im GUI rumklicken kann, intuition sei Dank. Nur das Programm reagiert halt nicht...

Und wenn man von einem Event-Scheduler ausgeht, der die zu den Events gehörenden Funktionen aufruft und keine durch UI-Events Verarbeitung an anderen Stellen verursachte Code-Doppelungen haben will, dann sind eigene Tasks/Threads für länger dauernde Aktionen der sauberste Weg.

mfg
--
Good coders do not comment. What was hard to write should be hard to read too.

[ - Antworten - Zitieren - Direktlink - ]

11.07.2006, 03:14 Uhr

DariusBrewka
Posts: 899
[Benutzer gesperrt]
Zitat:
Original von Holger:
Extrembeispiel wäre SFSSalv, bei dem man noch nicht einmal erkennen kann, ob es jetzt arbeitet oder abgestürzt ist, weil man immer noch munter im GUI rumklicken kann, intuition sei Dank. Nur das Programm reagiert halt nicht...


Ich galube das ist so ähnlich wie bei Windows, nur dass du dort i.A. nichtmal eine Reaktion erhälst ob geklickt wurde. Nur wundert sich man dort Teilweise nach mehreren Minuten dass nicht ein Klick vergessen wurde.


[ - Antworten - Zitieren - Direktlink - ]

11.07.2006, 03:49 Uhr

whose
Posts: 2156
Nutzer
Zitat:
Original von NoImag:
Deine Aussage war absolut. Nicht bei jeder längeren Aktion kann der User sinnvoll im selben Programm weiterarbeiten und um auf Abbruch zu reagieren, ist kein extra Task notwendig. Ok, du meinst das Programm kann bei Verwendung verschiedener Tasks leichter gewartet werden.


Hm, irgendwie siehst Du das Ganze wohl etwas zu simpel... Holgers Beispiel mit YAM machte doch eigentlich recht deutlich, worum es geht. Natürlich ist es nicht in jeder Situation in einem Programm sinnvoll, den User weiterhin irgendwelche sinnfreien Eingaben machen zu lassen. Beispiel wäre hier, bei einem Editor (wie auch schon von Holger erwähnt) den Text auf einem schweinelahmen Netzlaufwerk zu speichern und dem User die (völlig sinnfreie) Möglichkeit zu geben, den gleichen Text nochmal aufs gleiche Laufwerk zu speichern. Sinnvoll ists hingegen, im Text weiter arbeiten zu können. Oder eben bei YAM tatsächlich die laufende Übertragung abbrechen zu können (was ja, dank des blockierten GUIs bei YAM nicht möglich ist, so lange die Nachricht noch übertragen wird. Wenn die Übertragung aus Gründen, die nicht bei der lokalen Maschine zu suchen sind, klemmt, hat der Benutzer eine absolut nutzlose Abbruch-Funktion. Mit einem separaten Task fürs GUI und den Transfer hätte das benutzerfreundlicher gelöst werden können).

Zitat:
Zitat:
Jeden Task für sich macht es einfacher. Ein Hintergrund-Task, der von jeglichen GUI-Code freigehalten wird und ein GUI-Task, der nichts über die Art des Hintergrund-Tasks wissen muß.

Grundsätzlich leuchtet dies ein, aber wenn der Hintergrundtask eine Rückmeldung vom User benötigt, dann handelt man sich eine umfangreiche Kommunikation zwischen den Tasks ein.


Das hängt davon ab, welche "Rückmeldung vom User" Du dem Hintergrund-Task schicken willst. In den meisten Fällen reicht es völlig, den Task abbrechen oder neu starten zu können, der Task ist sozusagen "williger Sklave des GUI" und hat recht eingeschränkte Möglichkeiten (es macht halt keinen Sinn, diesen Task z.B. auf eine Eingabe im GUI direkt reagieren zu lassen oder gar IDCMP auszuwerten o.Ä. Er wartet nur auf Signale vom GUI-Task, z.B. "Leg los mit Rechnen, die Daten findest Du an gewohnter Stelle" oder "brich ab, womit Du gerade beschäftigt bist und warte auf neue Anweisungen". Ein schönes Beispiel für solche Konstrukte sind Raytracer. Sobald im Editor ein Objekt einer gerade in der Berechnung befindlichen Szene verändert wurde, bekommt der Trace-Task ein Signal, die Berechnung mit den neuen Daten neu zu starten und die bisher berechneten Daten zu verwerfen. Er braucht keine detaillierten Daten über User-Eingaben, muß sich nicht um die Einzelheiten der Dateneingabe durch den User kümmern, er berechnet einfach, was ihm vorgeworfen wird, wenns verlangt wird).

Für solche Zwecke genügen per Semaphore geschützte Flags und Speicherbereiche, da braucht es nicht einmal (relativ) kompliziertes Message-Handling. Schwieriger wird es erst, wenn Du Daten zur Berechnung übergeben willst, die Du nicht in einem gemeinsam genutzten Speicherbereich unterbringen kannst oder willst. Da werden dann recht umfangreiche Basteleien mit Inter-Task-Messages notwendig.

Mir fällt da aber jetzt auf Anhieb kein überzeugendes Beispiel ein, das auf diese Methode zwingend angewiesen wäre.

Zusammenfassend kann man wohl sagen, daß es manchesmal durchaus sinnvoll sein kann, das GUI und den großen Rest auf Task-Ebene zu trennen.

Grüße


--
---

:boing: µA1 PPC 750GX-800
:boing: A4000 PPC 604e-233

[ - Antworten - Zitieren - Direktlink - ]

11.07.2006, 20:05 Uhr

Holger
Posts: 8116
Nutzer
@whose:
Um Mißverständisse zu vermeiden: ich hatte mich bemüht, bei Yam-Beispiel in der Vergangenheitsform zu sprechen. Aktuelle Versionen sollten das Problem nicht mehr haben...

mfg
--
Good coders do not comment. What was hard to write should be hard to read too.

[ - Antworten - Zitieren - Direktlink - ]

11.07.2006, 20:08 Uhr

Holger
Posts: 8116
Nutzer
Zitat:
Original von DariusBrewka:
Ich galube das ist so ähnlich wie bei Windows, nur dass du dort i.A. nichtmal eine Reaktion erhälst ob geklickt wurde. Nur wundert sich man dort Teilweise nach mehreren Minuten dass nicht ein Klick vergessen wurde.


Bei den meisten Windows-Programmen wird dann auch das UI nicht mehr neu gezeichnet, wenn sie keine Events mehr verarbeiten.

Allerdings hängt das teilweise auch vom verwendete Toolkit ab (ok, wie beim Amiga ;) ).

Andererseits kann unter Windows nahezu jede Aktion zu einer längeren Aktion (in Computergrößenordnungen) werden, spätestens dann, wenn geswapt werden muß.

mfg
--
Good coders do not comment. What was hard to write should be hard to read too.

[ - Antworten - Zitieren - Direktlink - ]

11.07.2006, 20:57 Uhr

whose
Posts: 2156
Nutzer
Zitat:
Original von Holger:
@whose:
Um Mißverständisse zu vermeiden: ich hatte mich bemüht, bei Yam-Beispiel in der Vergangenheitsform zu sprechen. Aktuelle Versionen sollten das Problem nicht mehr haben...


Hmm, ich habe es zwar in der aktuellen Version auf meinem 4000er laufen, kann aber nicht wirklich sagen, ob sich diesbezüglich etwas verändert hat. Wenn, dann müßte es nun möglich sein, die Übertragung einer Nachricht wirklich abbrechen zu können, was ich in letzter Zeit nicht mehr ausprobiert habe. Sollte ich vielleicht einmal tun.

Früher war es ja so, daß der Abbruch nur nach der Übertragung einer vollständigen Nachricht möglich war...

Grüße

--
---

:boing: µA1 PPC 750GX-800
:boing: A4000 PPC 604e-233

[ - Antworten - Zitieren - Direktlink - ]

11.07.2006, 23:48 Uhr

NoImag
Posts: 1050
Nutzer
Zitat:
Original von Holger:
Merke: der User will vor allem dann gerne abbrechen, wenn die I/O-Operation nicht antwortet...


Stimmt, in so einem Fall macht ein Hintergrundtask Sinn. Allerdings bedeutet dies auch eine Kopie des Dokuments anlegen zu müssen, was eventuell erhebliche Resourcen erfordern kann (insbesondere beim Drucken). Hinzu kommt, dass ich beim Speichern in 19 Jahren noch nicht erlebt habe, dass ich das Speichern abbrechen wollte, bevor es bereits fertig war. Nenne mich ruhig faul, aber etwas, was so selten passiert zu berücksichtigen, kommt bei mir erst dran, wenn es sonst nichts mehr zu verbessern gibt.

Zitat:
Besser ist es. Weil Resourcen für die Faulheit des Programmiers zu verschwenden, gerade auf dem Amiga verpönt ist. Und auf Grafikkarten machen Smart-Refresh-Fenster, aufgrund der Notwendigkeit eines rückgerichteten Datentransfers, den Bus besonders lange dicht...

Naja, Smartrefresh-Fenster gibt es schon seit 1.x-Zeiten und damals war Resourcenschonung noch wirklich wichtig. Außerdem sollte man das Angebot des Betriebssystems einem Arbeit abzunehmen annehmen, sonst bräuchte man das Betriebssystem nicht. Was die Geschwindigkeit betrifft: Nach meiner Erfahrung machen Smartrefresh-Fenster unter AGA und CGFX das System schneller, nicht langsamer. Unter P96 sieht die Bilanz allerdings nicht ganz so eindeutig aus. Ein Grund weshalb ich P96 nicht benutze (außer zu Testzwecken).

Zitat:
Nicht umfangreicher als GUI-Code innerhalb einer Background-Aktion. Ich finde, z.B. innerhalb von DOS-Aufrufen hat GUI-Code nichts zu suchen.

So ein Aufwand ist der Aufruf eines Requesters nicht. Wie machst du das, wenn du testest, ob eine Datei schon existiert und du dann den User fragst, ob sie überschrieben werden darf?

Zitat:
Und ich gehe eigentlich immer von User-Aktion->Event->Programmaktion aus. Das ist für mich der "Amiga-Weg".
Hintergrundtask->Rückmeldung erfragen->User zu Aktion zwingen ist eher der "MsDOS-Weg".


Ein Unterschied ist mir da bisher nicht aufgefallen. Was machst du, wenn ein Fehler auftritt und es mehrere Möglichkeiten gibt fortzufahren? Den User die Reaktion vorher Konfigurieren zu lassen halte ich für eine schlechte Idee. Nach meiner Erfahrung entscheidet der User nämlich mal so und mal anders.

Tschüß


[ - Antworten - Zitieren - Direktlink - ]

12.07.2006, 00:09 Uhr

NoImag
Posts: 1050
Nutzer
Zitat:
Original von Holger:
Also evtl. machst Du ja alles richtig, in dem Du vor der längeren Aktion alle UI-Elemente deaktivierst, die jetzt nicht mehr möglich sind, evtl. die IDCMP-Maske anpaßt und während die "Hintergrund"aktion (also längere Vordergrundaktion) läuft, regelmäßig auf Abbruchtrigger überprüfst (und garantieren kannst, daß die Aktion nicht indirekt blockierend auf ein anderes Ereignis wie z.B. beim DOS warten kann).


Natürlichh blockiere ich alle Eingabemöglichkeiten, wenn das Programm beschäftigt ist. Ich schätze es nicht, wenn man bei einem Programm fleißig weiter rumklicken kann, obwohl es gar nicht in der Lage ist zu reagieren.
Was die Abbruch-Möglichkeiten betrifft: Da kannst du mich gerne Faul nennen. Operationen, die bei meiner praktischen Benutzung keine Sekunde dauern mit einer Abbruchmöglichkeit zu versehen, ist mir zuviel Arbeit, auch wenn die Operationen potentiell eine Stunde dauern können. Ich habe nicht den Anspruch alles perfekt zu machen. Man kann auch in Schönheit sterben. Abbrechen kann man daher nur das Drucken. Auf einen Hintergrundtask habe ich wegen des Resourcenverbrauchs verzichtet, auch wenn das die Gefahr birgt, dass auf das Abbrechen nicht sofort reagiert wird.

Zitat:
Hintergrund der absoluten Aussage ist die übliche Praxis eines Event-Handling Loops, bei dem die Abfolge "Nachricht holen"->Verarbeiten->Beantworten->"wieder von vorn" auch für länger dauernde Aktionen nicht verändert wird. Viele Programmierer denken ja noch nicht einmal darüber nach, was eine längere Aktion sein könnte.

Potentiell kann fast alles eine längere Aktion sein. Wenn man es luxuriös machen möchte, müsste deshalb für fast jede Aktion eine Abbruchmöglichkeit bestehen, wobei ein Abbruch-Requester natürlich nur mit Verzögerung geöffnet werden sollte.

Zitat:
Und wenn man von einem Event-Scheduler ausgeht, der die zu den Events gehörenden Funktionen aufruft und keine durch UI-Events Verarbeitung an anderen Stellen verursachte Code-Doppelungen haben will, dann sind eigene Tasks/Threads für länger dauernde Aktionen der sauberste Weg.

Dein MUI-Beispiel ist sicher so ein Fall, sofern man einen "ausradierten" Fensterinhalt nicht als unbedeutenden Schönheitsfehler hinnehmen möchte.

Tschüß


[ - Antworten - Zitieren - Direktlink - ]

12.07.2006, 00:16 Uhr

NoImag
Posts: 1050
Nutzer
Zitat:
Original von whose:
Das hängt davon ab, welche "Rückmeldung vom User" Du dem Hintergrund-Task schicken willst.


Ich denke da vor allem an Fehler, bei denen es mehrere Reaktionsmöglichkeiten gibt.

Zitat:
Zusammenfassend kann man wohl sagen, daß es manchesmal durchaus sinnvoll sein kann, das GUI und den großen Rest auf Task-Ebene zu trennen.

Dass eine eine Reihe von Fällen gibt, bei denen dies sinnvoll ist, habe ich nie bezweifelt. Ich unterscheide in der Regel mehrere Fälle: 1. Unbedingt notwendig 2. Empfehlenswert 3. Wünschenswert 4. Überflüssig.

Tschüß



[ Dieser Beitrag wurde von NoImag am 12.07.2006 um 00:17 Uhr geändert. ]

[ - Antworten - Zitieren - Direktlink - ]


-1- 2 [ - Beitrag schreiben - ]


amiga-news.de Forum > Programmierung > Fragen zu Intuition-Messages [ - Suche - Neue Beiträge - Registrieren - Login - ]


.
Impressum | Datenschutzerklärung | Netiquette | Werbung | Kontakt
Copyright © 1998-2024 by amiga-news.de - alle Rechte vorbehalten.
.