amiga-news DEUTSCHE VERSION
.
Links| Forums| Comments| Report news
.
Chat| Polls| Newsticker| Archive
.

amiga-news.de Forum > Programmierung > Drei Tasks arbeiten zusammen? [ - Search - New posts - Register - Login - ]

-1- [ - Post reply - ]

2014-08-06, 08:20 h

AGSzabo
Posts: 1663
User
Hi

ich habe drei Tasks. Der erste reagiert auf Benutzereingaben (GUI-Task) und startet ggf einen zweiten, der dann das aktuelle Directory in den Lister ein liest. Und es gibt noch einen dritten Task, der reagiert auf DOS-Notify Messages für das aktuell im Lister befindliche Verzeichnis und startet auch seinerseits ggf einen Dir-Lese Task, der den Lister zuerst leert und dann wieder befülllt.

Das scheint auch schon recht gut zu funktionieren, aber rein theoretisch habe ich Bedenken. Könnte es sein, dass ein Dir-lese-Task unter Umständen zweimal parallel gestartet wird, einmal durch einen Klick und ein andermal nochmal durch eine Message von DOS?

Ich habe es jetzt so, dass sowohl der GUI Task als auch der DOS-Notify Task den Lesetask, wenn er gerade läuft, vor dem Starten erstmal beendet. Dazu gibt es in einer Struktur, auf die der GUI Task wie auch der Notify Task zugriff haben, einen Zeiger auf den aktuellen Lesetask.

Aber brauche ich nicht noch eine Semaphore? Und wenn ja, sollte man sich die mit Attempt..() oder mit Obtain..() holen? Und zu welchem Zeitpunkt und wo sollte man die wieder frei geben?

--
Webmaster of Kestra Bitworld. Author of Open eXternal User Interfaces, eXternal Format Rippers and "Torakosmos".

[ - Answer - Quote - Direct link - ]

2014-08-06, 08:35 h

Thore
Posts: 2266
User
Wenn deine Daten statisch sind, brauchst Du eigentlich keine Semaphore. Nur wenn Du veränderliche Daten hast, auf die zwei Tasks zugreifen können, brauchst Du eine Semaphore.
Die Semaphore muss solange aufrechterhalten werden, solange die Gefahr besteht, daß zwei Tasks die gleichen Daten ändern können. Also freigeben wenn der Task mit seiner Aufgabe fertig ist. Jeder Task muss dann aber vor dem Zugriff erst die Sempahore prüfen und locken.
Benutzt Du nur ObtainSemaphore, dann wird das Programm auf die Freigabe des Semaphores warten. Willst du nicht warten, kannst Du mit AttemptSemaphore prüfen ob sie frei ist.

Je nach dem wie dein Programm arbeitet, kann es natürlich schon sein, daß dein Task zweimal gestartet wird. Ohne Debugging können wirs aber so nicht wissen.

[ - Answer - Quote - Direct link - ]

2014-08-06, 09:03 h

AGSzabo
Posts: 1663
User
@Thore:

Es kann und darf bei meinem Setup durchaus sein, dass der Lesetask von GUI gestartet, aber vom DOS Notify gestoppt wird. Das heißt, bevor die Gefahr besteht, dass zwei Tasks parallel meinen Lister befüllen, wird vorher damit aufgeräumt. Die Frage ist, ob ich nicht trotzdem ein Semafore brauche und wo. Sie zu locken bis das Dir eingelesen wurde, würde bedeuten, es kann nicht gestoppt werden?
--
Webmaster of Kestra Bitworld. Author of Open eXternal User Interfaces, eXternal Format Rippers and "Torakosmos".

[ - Answer - Quote - Direct link - ]

2014-08-06, 09:21 h

Thore
Posts: 2266
User
Richtig, wenn Du nur ObtainSemaphore verwendest, wird der Task warten bis sie frei ist. Mit Attempt kannst Du prüfen, ob schon einer den Lister befüllt, und entsprechend reagieren.
Du brauchst keine Semaphore, wenn Du es anders regelst, z.B. mit deinem Workaround. Sie sind aber bequem, nützlich und bieten schon alles was man für diesen Zweck braucht.
Für mehrere Threads oder Multithreading sind die Semaphoren sehr zu empfehlen.

Ach ja, wenn Dein Thread mit der Befüllung startet, dann der zweite kommt und seinerseits den Lister füllt, fängt es (so wie ich es rauslese) von vorne an. Das heißt es braucht in dem fall länger als nötig. Mit einer Semaphore kannst Du z.B. abfragen, ob der Lister befülllt wird, und diesen Part kann der zweite Thread dann überspringen, und auf das Füll-Ende warten.

[ Dieser Beitrag wurde von Thore am 06.08.2014 um 09:24 Uhr geändert. ]

[ - Answer - Quote - Direct link - ]

2014-08-06, 09:27 h

AGSzabo
Posts: 1663
User
@Thore:

Mein "Workaround" ist eigentlich die einzige Lösung, wenn man will, dass der Lesetask vom GUI UND vom DOS abgebrochen werden kann. Oder? Aber passt und reicht das auch wirklich? Immerhin könnte einer den andren nicht rechtzeitig erwischen?
--
Webmaster of Kestra Bitworld. Author of Open eXternal User Interfaces, eXternal Format Rippers and "Torakosmos".

[ - Answer - Quote - Direct link - ]

2014-08-06, 09:32 h

AGSzabo
Posts: 1663
User
Zitat:
Original von Thore:
Ach ja, wenn Dein Thread mit der Befüllung startet, dann der zweite kommt und seinerseits den Lister füllt, fängt es (so wie ich es rauslese) von vorne an. Das heißt es braucht in dem fall länger als nötig. Mit einer Semaphore kannst Du z.B. abfragen, ob der Lister befülllt wird, und diesen Part kann der zweite Thread dann überspringen, und auf das Füll-Ende warten.


Ja, es fängt dann von Vorne an. Ich könnte nun entweder warten, bis es fertig ist und dann nochmal füllen, aber mit der Info von DOS, oder einfach nichts tun, wobei vielleicht die Info von DOS verloren geht. Oder eben stoppen und neu starten, aber ich habe das Gefühl dass ich auch da etwas kurzzeitig locken muss.
--
Webmaster of Kestra Bitworld. Author of Open eXternal User Interfaces, eXternal Format Rippers and "Torakosmos".

[ - Answer - Quote - Direct link - ]

2014-08-06, 10:05 h

Thore
Posts: 2266
User
Nein, auch mit Semaphoren kann der laufende Thread/Task seine Aufgabe unterbrechen, z.B. wenn Du Signale abfragst. Er sollte dann aber auf jeden Fall noch ReleaseSemaphore aufrufen bevor er sich ganz beendet.

Aber wenn Du nur liest sind Semaphoren nicht so wichtig, weil die Daten ja gleichbleiben, also keine Gefahr besteht, daß z.B. zwei Threads auf die gleiche Adresse schreiben.

[ - Answer - Quote - Direct link - ]

2014-08-06, 16:49 h

Holger
Posts: 8116
User
Zitat:
Original von AGSzabo:
Ich habe es jetzt so, dass sowohl der GUI Task als auch der DOS-Notify Task den Lesetask, wenn er gerade läuft, vor dem Starten erstmal beendet.

Auf welche Weise?
Zitat:
Dazu gibt es in einer Struktur, auf die der GUI Task wie auch der Notify Task zugriff haben, einen Zeiger auf den aktuellen Lesetask.
Um was mit dem Task zu tun?
Zitat:
Aber brauche ich nicht noch eine Semaphore?
Kommt drauf an. Oftmals gibt es wesentlich einfachere Lösungen. Das hängt aber von der Antwort auf die oben gestellte Frage ab…

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

[ - Answer - Quote - Direct link - ]

2014-08-06, 17:10 h

AGSzabo
Posts: 1663
User
@Holger:

Auf welche Weise?

Der Lesetask schaut alle paar Files (ExAll mit Buffer für etwa 20 Files) ob er ein Signal erhalten halt und wenn ja geht er zum Ende.

ps: Das mache ich indem ich den Auslösenden Task erst weiter laufen lasse, wenn sich der Lesetask auch wirklich beendet hat.


Um was mit dem Task zu tun?

Um ihm das Signal zu setzen.
--
Webmaster of Kestra Bitworld. Author of Open eXternal User Interfaces, eXternal Format Rippers and "Torakosmos".

[ Dieser Beitrag wurde von AGSzabo am 06.08.2014 um 17:30 Uhr geändert. ]

[ - Answer - Quote - Direct link - ]

2014-08-06, 21:05 h

Holger
Posts: 8116
User
Gut zu wissen. Daraus ergibt sich folgender, bereits in der Praxis bewährter Lösungsansatz: statt Tasks zu starten und zu beenden, wird genau ein Task gestartet und die gesamte Lebensdauer des Programms behalten, oder zumindest so lange, wie mindestens einer, das GUI oder der DOS-Notify Task, noch existieren.

Ein zusätzlicher Task, der schläft, während er keine Aufgaben hat, ist gerade im AmigaOS überhaupt keine Bürde.

Für den Lesetask ergibt sich somit nur die kleine Änderung, dass er nach dem vollendeten Lesen auf ein neues Signal wartet und dann wieder von vorne beginnt.

Da sich der Task nicht ändert, müssen die Trigger Tasks auch keine Semaphoren oder ähnliches benutzen, um ein Signal zu senden.

Noch einfacher wird es, wenn man für die Kommunikation wird einfach einen MessagePort verwendet, der ebenfalls die gesamte Zeit über existiert. Ein MessagePort kapselt letztendlich ein Signal und fügt die Features, Informationen senden und Antwort zurücksenden hinzu, ohne wesentlichen Overhead gegenüber der simplen Signal-Verwendung zu erzeugen. Im Gegenteil, man spart sich dasselbe auf möglicherweise ineffizientere Weise von Hand zu programmieren. Beide Trigger Tasks senden einfach Messages an Lesetask, der nun nicht nach einem Signal, sondern einer neuen Message fragt.

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

[ - Answer - Quote - Direct link - ]

2014-08-06, 21:34 h

AGSzabo
Posts: 1663
User
@Holger:

Ah, das liest sich gut! Na also die Messages werde ich wohl nicht brauchen, da der Lesetask keine Parameter hat.

Der Lesetask braucht nur auf ein Signal "Lese!" zu warten und während er liest auf ein Signal "Stop!". Oder?

Wann sollte das Signal "Stop!" gesetzt werden? Wenn ich es pauschal vor jedem Lesen mache, dann bricht der Lesetask gleich wieder ab, weil das Signal über das "Start!" hinweg erhalten bleibt?

Falls ich es doch mit Messages mache, würde dann nicht der Lesetask garnicht aufhören bis er alles gelesen hat?

Vielleicht könnte ich den Notify Task gleich auch für das Lesen mitverwenden?
--
Webmaster of Kestra Bitworld. Author of Open eXternal User Interfaces, eXternal Format Rippers and "Torakosmos".

[ Dieser Beitrag wurde von AGSzabo am 06.08.2014 um 21:34 Uhr geändert. ]

[ - Answer - Quote - Direct link - ]

2014-08-06, 21:50 h

AGSzabo
Posts: 1663
User
Ah wir haben noch etwas übersehen:

Es können mehrere Lister zur selben Zeit offen sein! Das heißt, jeder Lister braucht seinen eigenen Lesetask? Den Notify-Task kann ich dann nicht zum lesen verwenden, denn den gibt es nur einmal für alle.

Ich komme damit auf jede Menge Tasks:

- Die Anwendung selber
- Ein "Job Task" in der Anwendung, der auf Messages wartet und je nachdem was da so kommt verschiedene Dinge tut
- Ein "Ripper" Task in der Anwendung, der geladene Files durchsucht

- In der Filemanager-Klasse einen Servertask für deren GUIs
- Eben in dieser Klasse auch noch einen DOS-Notify Task
- offenbar pro offenem Filer einen wartenden Lesetask

Kann man das irgendwie optimieren? :D Wobei, ich finds gut .. :)
--
Webmaster of Kestra Bitworld. Author of Open eXternal User Interfaces, eXternal Format Rippers and "Torakosmos".

[ - Answer - Quote - Direct link - ]

2014-08-07, 14:50 h

Holger
Posts: 8116
User
Zitat:
Original von AGSzabo:
Der Lesetask braucht nur auf ein Signal "Lese!" zu warten und während er liest auf ein Signal "Stop!". Oder?

Nein, er braucht nur ein Signal, das für „Lesen“ und „Neustarten“ gleichermaßen steht. Wenn das Signal empfangen wird, wird es natürlich zurückgesetzt.

Nur für das final Aufräumen gibt es ein eigenes Signal (wenn man keine Messages verwendet).
Zitat:
Falls ich es doch mit Messages mache, würde dann nicht der Lesetask garnicht aufhören bis er alles gelesen hat?
Wieso? Statt zu überprüfen, ob das Signal Bit gesetzt ist, prüft er, ob eine neue Message angekommen ist.
Zitat:
Vielleicht könnte ich den Notify Task gleich auch für das Lesen mitverwenden?
Das ist natürlich prinzipiell möglich.

Zitat:
Original von AGSzabo:
Es können mehrere Lister zur selben Zeit offen sein! Das heißt, jeder Lister braucht seinen eigenen Lesetask?

Das ist der Moment, wo Messages ins Spiel kommen, die dem Lesetask mitteilen, welches Verzeichnis er lesen soll.

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

[ - Answer - Quote - Direct link - ]

2014-08-07, 20:15 h

AGSzabo
Posts: 1663
User
@Holger:

Aha, das mit dem nur einen Signal für stop/restart finde ich auf den ersten Blick sehr gut. Aber was wenn ich den Lesevorgang nur abbrechen will, der Task aber erhalten will?
--
Webmaster of Kestra Bitworld. Author of Open eXternal User Interfaces, eXternal Format Rippers and "Torakosmos".

[ - Answer - Quote - Direct link - ]

2014-08-08, 08:53 h

Thore
Posts: 2266
User
Dann schickst Du ein entsprechendes Stop-Signal. Der Task springt dann aus dem Lesevorgang raus zurück in den Idle Modus wo er vorher war.

[ Dieser Beitrag wurde von Thore am 08.08.2014 um 08:53 Uhr geändert. ]

[ - Answer - Quote - Direct link - ]

2014-08-08, 10:55 h

AGSzabo
Posts: 1663
User
Ok, Danke an alle Beteiligten, ich hab's hin bekommen! Bis zum nächsten Mal. ;)
--
Webmaster of Kestra Bitworld. Author of Open eXternal User Interfaces, eXternal Format Rippers and "Torakosmos".

[ - Answer - Quote - Direct link - ]

2014-08-08, 11:40 h

Thore
Posts: 2266
User
Vergess beim rausspringen aus Routinen nicht, evtl reservierten Speicher freizugeben. Sonst hast Leaks drin die sich aufschaukeln

[ - Answer - Quote - Direct link - ]

2014-08-08, 13:34 h

AGSzabo
Posts: 1663
User
Ah, da ist noch ein Problem:

ich habe einen Modus, in dem Starte ich den Filerequester als Manager. Der hat dann keine select/cancel Buttons und reagiert ein bisschen anders auf Benutzeraktionen. Der Aufrufende Task muss dann auch nicht warten, bis der Manager geschlossen ist, sondern darf nach dem Öffnen des Managers weiter machen.

Das klappt soweit wunderbar. Jetzt möchte ich aber, dass der Manager beim Click auf's Closegadget disposed wird. Das löst bei mir ein Event aus, innerhalb dessen Bearbeitungscode sich der Manager selbst disposen könnte. Das geht aber nicht, weil die Eventbearbeitung an Daten gebunden ist, die im Manager-Objekt selber sich befinden, Dispose ich das Objekt, sind die Daten weg und der Eventbearbeiter läuft in's Nirvana.

Damit das trotzdem klappt, habe ich eine zweite Art von "Dispose()" eingeführt, die "DynamicDispose()" Funktion. Diese setzt ein Bittebit im Objekt, dass das Obkekt disposed werden soll, und entfernt es erst - naja - im nächsten Refresh-Run. Aber das Filer-Objekt bekommt von dem Refresh garnix mit, weil es nicht am Fenster hängt sondern einfach nur ein Objekt ist (mit seinem eigenen Fenster und dann wieder viele refreshbare Objekte da drin).

Kann man das irgendwie anders und besser machen?

A
--
Webmaster of Kestra Bitworld. Author of Open eXternal User Interfaces, eXternal Format Rippers and "Torakosmos".

[ Dieser Beitrag wurde von AGSzabo am 08.08.2014 um 13:48 Uhr geändert. ]

[ - Answer - Quote - Direct link - ]

2014-08-08, 17:36 h

Holger
Posts: 8116
User
@AGSzabo:
Ich komm da nicht mehr mit.

Wer bearbeitet denn das Dispose-Event, wenn nicht der Event-Bearbeiter?

Und wenn, wer auch immer, das Dispose in ein „DynamicDispose“ umgewandelt hat und dann, ich weiß nicht, über wen wir jetzt sprechen, auf das Bittebit im nächsten Refresh-Run reagiert und somit das eigentliche dispose durchführt, wieso kann dann nicht letztgenannter ein entsprechendes Dispose an das Filer-Objekt schicken?

Mich deucht, entweder ist die Struktur ziemlich chaotisch oder Du hast Schwierigkeiten, sie zu beschreiben. Wobei letzteres meistens dann doch wieder ein Zeichen für ersteres ist.

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

[ - Answer - Quote - Direct link - ]


-1- [ - Post reply - ]


amiga-news.de Forum > Programmierung > Drei Tasks arbeiten zusammen? [ - Search - New posts - Register - Login - ]


.
Masthead | Privacy policy | Netiquette | Advertising | Contact
Copyright © 1998-2024 by amiga-news.de - all rights reserved.
.