home *** CD-ROM | disk | FTP | other *** search
- .. //////////////////////////////////////////////////////////////////
- .. /// Dokumentation zum Multi-Tasking Subsystem V2.10 / April 1990
- .. /// Modul MTPIPE
- .. /// Format: DOCLIST 1.00-Format
- .. //////////////////////////////////////////////////////////////////
- .. /// Bitte passen Sie die nachfolgenden Zeile ggf. für Ihren
- .. /// Drucker an. Die Voreinstellung paßt auf einen EPSON FX-85
- .. /// mit Papierformat 12"
- .. //////////////////////////////////////////////////////////////////
- .PL 72 Seitenlänge 72 Zeilen
- .LL 80 Zeilenlänge 80 Zeichen
- .ID 5 Einrücken um 5 Zeichen vom linken Rand
- .RM 5 5 Zeichen bis zum rechten Rand Platz lassen -> 70
- .. Zeichen Text je Zeile
- .HS = Zeichen für Kopf-/Fuß-Trenner
- .RS - Zeichen für Trennung von Referenz-Einträgen
- .CO (c) Copyright 1988..1990 Ch.Philipps Software-Technik
- .. //////////////////////////////////////////////////////////////////
- .SE Multi-Tasking Subsystem für Turbo-Pascal 5.x Version 2.10
-
-
-
-
-
-
-
-
- Turbo Pascal 5.x Multi-Tasking Subsystem
-
-
- MTPIPE - Benutzerhandbuch
-
-
-
-
-
-
-
-
- (c) Copyright 1988, 1989, 1990
-
- Christian Philipps Software-Technik
-
- alle Rechte vorbehalten
-
-
- Version 2.10 / April 1990
-
-
-
-
-
-
-
-
-
-
-
-
- Anschrift: Christian Philipps
- Software-Technik
- Düsseldorfer Str. 316
-
- D-4130 Moers 1
-
- Telefon..: 02841 / 35932
- Fido-Netz: 509/3.4
-
- .SE Lizenzvereinbarung, Garantie- und Haftungsausschluß, Warenzeichen
- siehe hierzu CPMULTI.DOK
- .SE MTPIPE / Leistungsbeschreibung
- 1. Leistungsbeschreibung
-
- Die Zusatzunit MTPipe beinhaltet einen Turbo Pascal Textdatei-
- Gerätetreiber für die Verwaltung von "Named Pipes".
-
- Es können dem zur Verfügung stehenden Heap-Space entsprechend viele
- Pipes angelegt werden, auf die konkurrierend mit mehreren Tasks
- schreibend bzw. lesend zugegriffen werden kann.
-
- Der Datenaustausch über die Pipe erfolgt mittels der Standard Pascal
- Prozeduren Read/Readln bzw. Write/Writeln, wobei die Pipe wie eine
- Textdatei behandelt wird. Evtl. auftretende Fehler können mittels
- IOResult behandelt werden.
-
- Der Pipe-Treiber sorgt allein für die Synchronisation des Daten-
- transfers, wodurch die Pipe zu einem sehr einfach zu benutzenden
- Kommunikationsmedium wird.
-
-
- Hinweis für registrierte Anwender des Multi-Tasking Subsystems
- --------------------------------------------------------------
-
- Bitte beachten Sie, daß für diese Unit gleichfalls die Lizenzver-
- einbarungen gelten, die in der Dokumentation zum Multi-Tasking Sub-
- system aufgeführt sind.
- Insbesondere bedeutet dies, daß Sie die lizenzierte Version dieses
- Produktes, seine Dokumentation und seinen Quellcode unter keinen
- Umständen an Dritte weitergeben dürfen, weder auszugsweise, noch
- vollständig. Diese Unit einschließnlich ihrer Dokumentation ist, wie
- auch CPMulti, in der lizenzierten Version KEINE ShareWare, sondern
- ausschließlich gemäß den Lizenzvereinbarungen (siehe CPMULTI.DOK) zu
- behandeln.
- .SE MTPIPE / Einbindung der Unit
- 2. Einbindung der Unit in eigene Programme
-
- Wie beim Multi-Tasking-Subsystem selbst, gestaltet sich auch hier die
- Einbindung unproblematisch. Durch einen entsprechenden Eintrag in der
- USES-Klausel Ihres Programmes, wird MtPipe integriert. Beim Start
- des Anwendungsprogrammes initialisiert sich MtPipe selbst.
-
- Beispiel: USES CPMULTI, MtPipe;
-
- Bitte beachten Sie die Reihenfolge der Einbindung, die in Kapitel 8
- des Handbuches zu CpMulti angegeben ist.
- .SE MTPIPE / Konzept
- 3. Konzept
-
- Eine Pipe bildet einen Einweg-Kommunikationskanal zwischen zwei
- Prozessen. Bezogen auf zwei Kommunikationspartner, ist stets ein
- Partner der Schreibende und der andere Partner der Lesende. Niemals
- kann ein Prozeß gleichzeitig in eine Pipe schreiben und auch wieder
- aus ihr lesen.
-
- Eine Pipe wird mittels einer speziellen Assign Prozedur (Assign-
- Pipe), ähnlich der Standard-Prozedur Assign einer Dateivariablen vom
- Typ "Text" zugeordnet und kann anschließend mittels Reset, Rewrite
- oder Append lesend bzw. schreibend eröffnet werden. Zu beachten ist
- hierbei, daß im Gegensatz zu Dateien, der Inhalt der Pipe durch
- Rewrite nicht gelöscht wird. Rewrite und Append verhalten sich im
- Hinblick auf die Pipe funktionsgleich.
-
- Jede Task, die eine Pipe eröffnen möchte, benötigt hierzu eine
- EIGENE Dateivariable vom Typ "Text". Kommunizieren z. B. 5 Tasks
- miteinander über eine Pipe, so existieren für diese Pipe 5 eröffnete
- Dateivariablen, die jedoch auf ein und dieselbe Pipe verweisen. Wie
- wird dies bewerkstelligt?
-
- Ähnlich der Standardprozedur "Assign", existiert für Pipes eine
- spezielle Funktion mit Namen "AssignPipe" deren Aufgabe es ist, die
- Verbindung zwischen einer Dateivariablen und den internen Daten-
- strukturen einer Pipe herzustellen.
- Beim Assign wird der Pipe ein Name gegeben, der im System eindeutig
- sein muß. Über diesen Namen können sich später andere Prozesse an
- eine bereits bestehende Pipe "anhängen". Eine Pipe wird automatisch
- erzeugt, wenn ein Prozeß einen Assign-Aufruf mit einem Pipe-Namen
- absetzt, der im System noch nicht vorhanden ist. Ist zum Zeitpunkt
- des Assign bereits eine Pipe mit dem angegebenen Namen vorhanden, so
- wird der anfordernde Prozeß an diese angeschlossen.
-
- Nach erfolgreichem Öffnen der Pipe, können Daten mittels Write oder
- Writeln in diese geschrieben werden (eröffnet mit Rewrite oder
- Append) bzw. mittels Read oder Readln aus dieser gelesen werden
- (eröffnet mit Reset). Bitte lesen Sie den Abschnitt 7 (Programmier-
- hinweise) dieser Dokumentation gründlich, bevor Sie die ersten Ver-
- suche mit Pipes starten. Auch das Studium des Demoprogrammes FINDER
- ist sehr sinnvoll.
-
- Die Datenspeicherung innerhalb der Pipe erfolgt in einem Ringpuffer,
- dessen Größe beim Erzeugen der Pipe festgelegt wird und der
- dynamisch auf dem Heap zugewiesen wird. Der Zugriff auf diesen
- Ringpuffer wird, für die Kommunikationspartner unsichtbar, über
- Semaphoren synchronisiert.
- Wann immer ein Prozeß aus einer Pipe lesen möchte, die keine Daten
- enthält, wird er bis zum Eintreffen von Daten blockiert.
- Andererseits wird ein Schreiber blockiert, wenn nicht ausreichen
- Platz in der Pipe vorhanden ist, um seine gesamten Daten aufzunehmen.
-
- Zu jedem Zeitpunkt können theoretisch mehrere lesende und mehrere
- schreibende Prozesse gleichzeitig Zugriff auf eine Pipe ausüben.
- Praktisch sinnvoll ist in der Regel jedoch nur die Kombination
- mehrerer schreibender Prozesse mit einem Leser (siehe FINDER).
-
- Im Normalfall werden zu einer Pipe immer mindestens zwei Prozesse
- existieren, die diese Pipe als Kommunikationskanal nutzen. Einer
- füllt die Pipe mit Daten; der Andere entnimmt diese wieder und ver-
- arbeitet sie weiter.
- Sehr häufig wird irgendwann einmal ein Punkt erreicht, an dem der
- schreibende Prozeß seine Aufgabe beendet hat und keine weiteren
- Daten mehr liefert. Normalerweise wird er seine Seite der Pipe
- schließen und sich beenden oder andere Aufgaben wahrnehmen. Ohne
- besondere Vorkehrungen, würde dies für den lesenden Prozeß bedeuten,
- daß dieser blockiert würde, sobald er alle Daten aus der Pipe
- verarbeitet hat und in diesem Zustand für den Rest seines Lebens
- handlungsunfähig verbleiben müßte.
- Dies ist offensichtlich nicht wünschenswert. Vielmehr wäre es
- sinnvoll, den Leser mittels eines geeigneten Signals darauf
- hinzuweisen, daß keine Gegenstelle mehr existiert. Es wäre z. B.
- praktisch, in diesem Fall eine EOF-Bedingung zu erzeugen. Aus
- technischen Gründen hat sich diese Möglichkeit in Verbindung mit
- TEXT-Dateien nicht bewährt. Dies liegt in der internen Struktur der
- EOF-Funktion von Turbo Pascal begründet und soll hier nicht näher
- diskutiert werden.
- Der Pipe-Treiber liefert im Falle von Schreibzugriffen auf eine
- Pipe, zu der kein weiterer Prozeß Zugang hat, den Fehler 101
- (Platten-Schreibfehler) und bei Lesezugriffen auf eine Pipe ohne
- Gegenstelle den Fehler 100 (Platten-Lesefehler). An Stellen, an
- denen die o. g. Situation auftreten kann, muß nach jedem Zugriff auf
- die Pipe mittels IOResult der Fehlerstatus abgefragt werden!! Auch
- setzt dies voraus, daß der Compiler-Schalter I- gesetzt ist.
-
- Lassen Sie mich nun den Faden noch einmal weiterspinnen: Es ist
- durchaus denkbar, daß der lesende Prozeß eine höhere Priorität
- besitzt als der Schreiber. In diesem Fall wird er stets die gesamte
- Pipe entleeren und beim folgenden Lesezugriff blockiert. Erst dann
- kommt der Schreiber wieder zum Zuge, um neue Daten in die Pipe zu
- schreiben. Es ist nun sehr wahrscheinlich, daß der Leser bereits
- wieder im Zustand der Blockierung auf Daten wartet, wenn der
- Schreiber seine Seite der Pipe schließt, da er keine weiteren Daten
- zu liefern hat. In diesem Fall wird der "schlafende" Leser
- reaktiviert und erhält die Fehlermeldung 100. Gleiches geschieht,
- wenn ein schreibender Prozeß auf Freispeicher in der Pipe wartet und
- die Gegenstelle ihre Seite der Pipe schließt; der Schreiber erhält
- wiederum den Fehler 101.
-
- Die letzten Abschnitte gehören genaugenommen bereits in das Kapitel
- "Realisierung". Ich habe sie jedoch bewußt vorgezogen, um denjenigen
- Anwendern, die die Datails des Treibers nicht weiter interessieren,
- das Studium des Kaptitels 4 ersparen zu können.
- Wenn Ihnen nur an der Anwendung der Unit gelegen ist, so können Sie
- nun getrost zum Kapitel 5 übergehen.
- .SE MTPIPE / Realisierung
- 4. Realisierung
-
- Die Unit DOS definiert einen Record namens "TextRec", der das wesent-
- liche Bindeglied zwischen einem TEXT-Datei Treiber und den Standard-
- Funktionen/Prozeduren zur Dateiein-/ausgabe herstellt.
- Dieser Record ist im zweiten Band Ihres Turbo Pascal Handbuches
- ausführlich beschrieben. Strukturell verbirgt sich hinter dem
- Dateityp "Text" nichts anderes, als eben dieser "TextRec". Im
- Folgenden verwende ich daher die Begriffe "Dateivariable" und
- "TextRec" als Synonyme.
-
- Wie bereits erwähnt, existiert für jede Verbindung zu einer Pipe eine
- separate Dateivariable vom Tpy "Text". Diese enthält u. a. einen
- Default-Puffer mit einer Größe von 128 Bytes sowie Felder, in denen
- der Modus (Lesend/Schreibend) sowie der Füllstand des Puffers
- abgelegt werden. Weiterhin ist auch ein Bereich für den mit dieser
- Dateivariablen verbundene Dateinamen vorgesehen.
-
- Die Verbindung zwischen einem TEXT-Datei Gerätetreiber und der
- Dateivariablen wird über eine Reihe von Pointerfeldern im "TextRec"
- hergestellt, die auf die Treiberroutinen zum Öffnen, Schließen
- und Datentransfer verweisen. Die Adressen dieser Routinen müssen
- dort von der Assign-Routine bzw. der Open-Routine des Treibers
- hinterlegt werden.
-
- Neben den festen Bestandteilen existiert noch ein Feld "UserData",
- welches der Programmierer eigener Gerätedateitreiber redefinieren und
- nach Belieben verwenden kann. Der Pipe-Treiber verwendet dieses Feld
- in erster Linie dazu, eine Verbindung zwischen den einzelnen
- Dateivariablen der Kommunikationspartner und den internen
- Datenstrukturen der Pipe herzustellen.
-
- Bildhaft könnte man sich dies wiefolgt vorstellen:
-
-
- ┌───────────────────┐
- │Task 1 (schreibend)│
- │ │
- │ │
- │VAR SPipe : TEXT │
- └──────┬────────────┘
- │
- │
- ┌──────┴───────────┐ ┌─────────────────┐
- │Pipe-Verwaltungs- ├────────────────┤Pipe-Datenbereich│
- │struktur │ │ │
- └──────┬───────────┘ │ │
- │ │ │
- │ │ │
- ┌──────┴────────────┐ │ │
- │VAR LPipe : TEXT │ │ │
- │ │ │ │
- │ │ │ │
- │Task 2 (lesend) │ └─────────────────┘
- └───────────────────┘
-
-
- Die Pipe-Verwaltungsstrukturen aller im System befindlichen Pipes
- werden mittels der Unit Queue in Form einer doppelt verketteten
- Liste verwaltet. Ein Zeiger auf den zugehörigen Verwaltungssatz wird
- in jeder angeschlossenen Dateivariablen (im Feld UserData) hinterlegt.
-
- Der Verwaltungssatz enthält u. a. ein Namensfeld, dessen Inhalt als
- identifizierendes Merkmal verwendet wird, einen Zeiger auf den
- Datenbereich der Pipe sowie fünf Semaphoren, die den Zugriff auf die
- Pipe synchronisieren. Die Anzahl der aktuell eröffneten Kommunika-
- tionskanäle zu einer Pipe werden in einem Zählfeld verwaltet. Anhand
- dieses Zählers kann der Treiber feststellen, ob zum Zeitpunkt eines
- Zugriffs auf die Pipe noch weitere Kommunikationspartner existieren.
- Der Rest des Verwaltungssatzes wird für die Überwachung des
- Datenbereiches (Füllstand, etc.) benötigt.
-
- Der für den Verwaltungssatz und den Datenbereich der Pipe benötgte
- Speicherplatz wird auf dem Heap reserviert. Ist nicht ausreichend
- Speicher vorhanden, so liefert die Assign-Funktion einen Fehler
- zurück.
-
- Sobald der letzte Kommunikationspartner die Pipe geschlossen hat,
- wird diese aus dem System entfernt; der dynamisch angelegte Speicher
- wird wieder freigegeben.
- .SE MTPIPE / Exportierte Typdefinitionen
- 5. Exportierte Typdefinitionen
-
- PipeNameType = String[8];
- .SE MTPIPE / Referenz
- 6. Funktionsbeschreibung (alphabetisch)
-
-
- .RE AssignPipe
- Deklaration
-
- FUNCTION AssignPipe(VAR PT:Text; PName:PipeNameType; PSize:Word;
- RequestSize:Byte; AlwaysBlock:WaitFlagType):BOOLEAN;
-
- Funktion
-
- Erzeugen einer Pipe bzw. Anmelden an eine bereits vorhandene Pipe.
- Der erste Parameter "PT" bezeichnte die TEXT-Dateivariable, über
- die die Kommunikation mit der Pipe stattfinden soll. JEDE Task,
- die auf eine Pipe zugreift, besitzt eine EIGENE Dateivariable!!!
- "PName" enthält den Namen, unter dem die Pipe im System bekannt
- ist. Existiert diese Pipe bereits, so wird der aufrufende Prozeß
- mit dieser verbunden. In diesem Fall ist der Parameter "PSize"
- ohne Belang.
- Ist unter dem angegebenen Namen (Groß- und Kleinschreibung werden
- unterschieden!!!!!) noch keine Pipe im System vorhanden, so wird
- sie mit einem Datenbereich in der Größe "PSize" angelegt. "PSize"
- muß in diesem Fall MINDESTENS 128 betragen.
- Der Parameter "RequestSize" gibt an, wieviele Zeichen auf einmal
- zwischen dem Puffer der Dateivariablen und dem Datenbereich der
- Pipe hin und her übertragen werden. Ist dieser Wert 0, so wird
- standardmäßig der Wert 128 (entsprechend der Größe des Puffers der
- Dateivariablen) eingesetzt. Dies ist auch der maximal zulässige
- Wert für diesen Parameter.
- Der letzte Parameter, "AlwaysBlock", kann die Werte "Wait" und
- "NoWait" annehmen. Diese Angabe bezieht sich auf das Verhalten
- eine Task wenn sie auf eine Pipe zugreift, zu der keine
- Gegenstelle mehr vorhanden ist. "NoWait" bewirkt die sofortige
- Rückkehr mit einem Fehlercode (100/101). "Wait" bewirkt, daß die
- Task blockiert wird und solange blockiert bleibt, bis eine
- Gegenstelle existiert und sie durch Füllen/Leeren der Pipe
- reaktiviert.
-
- ACHTUNG!!!!
- Unabhängig vom Parameter "AlwaysBlock", wird eine Task mit einem
- Fehler reaktiviert, falls sie gerade blockiert ist, wenn der letzte
- Kommunikationspartner seine Seite der Pipe schließt!!
-
- AssignPipe liefert den Wert TRUE, wenn die Aktion erfolgreich
- durchgeführt werden konnte. Im Fehlerfall wird FALSE geliefert.
- Fehler deuten auf eine falsche Angabe in "PSize" hin oder darauf,
- daß nicht ausreichen Heap-Space zur Verfügung stand.
-
- Beispiel
-
- .......
-
- IF NOT AssignPipe(Lst,'MtPrinter',0,1,NoWait)
- THEN MtPrintError(ErrAsgn)
- ELSE Reset(Lst);
-
- .......
-
- Kommentar
-
- Der Parameter "RequestSize" ist in der Mehrzahl der Fälle
- vollkommen ohne Belang, da er lediglich den internen Datentransfer
- zwischen TEXT-Record und Pipe regelt. Der Anwender bekommt diese
- automatisch ablaufenden Vorgänge nicht mit.
- Kleinere Werte als die Standardgröße von 128 Bytes bewirken
- normalerweise nur eine Verschlechterung der Performance, da mehr
- Aufrufe der Treiber-Funktionen erforderlich werden, um die gleiche
- Menge an Daten zu transportieren.
- Zuweilen jedoch, z. B. im Print-Spooler, kann es wichtig sein, die
- maximal bei jedem Aufruf transferierte Zeichenmenge zu begrenzen.
- Der Print-Spooler, der ja performance-unkritisch im Hintergrund
- Zeichen zum Drucker schickt, setzt diese Grenze auf 1 Byte herab.
- Dadurch kann der Druckoutput nach jedem Zeichen bei Bedarf ge-
- cancelled werden.
-
- Noch ein Wort zur "RequestSize". Wie bereits erwähnt, ist der
- Maximalwert für die RequestSize 128. Für Textdateien existiert die
- Prozedur SetTextBuf, die es erlaubt, einen größeren Übertragungs-
- puffer zur Verfügung zu stellen. Dies hilft bei der Übertragung
- großer Datenmengen, die Anzahl Plattenzugriffe zu reduzieren.
- SetTextBuf ist auch auf Pipes anwendbar, wenngleich sie dort,
- aufgrund fehlender Plattenzugriffe, nicht allzuviel Sinn macht.
- Möchten Sie einen größeren Puffer und somit einen größeren Wert
- für RequestSize (>128) verwenden, so ist SetTextBuf NACH dem
- Aufruf von AssignPipe, jedoch VOR dem Aufruf von Reset/Rewrite/
- Append auf die Dateivariable anzuwenden. RequestSize wird dadurch
- automatisch auf die Größe des von Ihnen angegebenen Puffers erhöht.
- .EE
- ────────────────────────────────────────────────────────────────────
- .RE ExistPipe
- Deklaration
-
- FUNCTION ExistPipe(PName:PipeNameType):BOOLEAN;
-
- Funktion
-
- Prüfe, ob bereits eine Pipe unter dem angegebenen Namen existiert.
- Dies kann u. U. nützlich sein, wenn ein Prozess nur die Pipe lesen
- möchte. Durch den Assign würde diese jedoch bereits physisch angelegt,
- was aber nicht immer wünschenswert ist.
- .SE MTPIPE / Programmierhinweise
- 7. Programmierhinweise
-
- Größenangaben
-
- Versuche, eine Pipe mit einer Puffergröße (PSize) < 128 Bytes
- anzulegen, führen beim Assign zu einem Fehler. Diese Aussage bezieht
- sich nur auf einen Assign-Befehl für eine noch nicht vorhandene
- Pipe. Ist unter dem angegebenen Namen bereits eine Pipe aktiv, so
- wird der Parameter PSize nicht beachtet.
-
-
- Read/ReadLn und Write/Writeln
-
- Mit den o. a. Prozeduren lassen sich sowohl Strings als auch
- Einzelzeichen (CHAR) und numerische Daten über Pipes austauschen. Es
- ist jedoch zu beachten, daß der Empfänger lediglich mit einem
- unstrukturierten Datenstrom einzelner Bytes konfrontiert wird, d. h.
- im Normalfall nicht zwischen diesen Datentypen unterscheiden kann.
- Dem Empfänger muß also bekannt sein, welche Datentypen er in welcher
- Reihenfolge in er Pipe erwarten kann. Das Programm FINDER kann als
- gutes Beispiel für den gemischten Austausch verschiedener Datentypen
- über eine Pipe dienen.
-
- Im Hinblick auf numerische Datentypen, verhält sich die Pipe ähnlich
- der Tastatur bei der normalen Eingabe mittels Read.
-
- Beispiel: Read(NumVar) --> Eingabe: 1234a --> Fehler 106 (ungülti-
- ges Zahlenformat)
- dagegen.: Read(NumVar) --> Eingabe: 1234 a --> 1234 wird erkannt
-
- Ein numerisches Datum muß also durch mindestens eine Leestelle von den
- nachfolgenden Daten getrennt werden. Das oder die Leerzeichen
- verbleiben allerdings in der Pipe und werden dem nachfolgenden Datum
- zugerechnet.
-
- Strings sollten möglichst mittels WriteLn in die Pipe geschrieben
- und mittels ReadLn aus dieser gelesen werden. Der Grund für diese
- Empfehlung ist, daß Strings nur in ihrer tatsächlichen Länge
- geschrieben werden, jedoch die Prozedur Read versucht, die dem
- Zieldatentyp (Zielstring) entsprechende Maximalanzahl von Zeichen zu
- lesen.
-
- Beispiel: VAR Ziel : String[85];
- N : Byte;
-
- For N := 1 TO 5 DO
- Write(Pipe,'Dies ist ein Test');
- Read(Pipe,Ziel);
- Writeln(Ziel);
-
- Als Ergebnis würden auf dem Bildschirm die fünf Quellstrings
- unmittelbar hintereinander, d. h. ohne jegliches Trennzeichen,
- ausgegeben. Read hat keinerlei Möglichkeit festzustellen, daß sich
- die Quelldaten aus fünf Einzelstrings à 17 Zeichen zusammensetzen
- und füllt daher den Zielpuffer in seiner maximalen Länge.
-
- Im Gegensatz dazu, wird durch Verwendung von WriteLn für Strings ein
- Zeilenende-Zeichen explizit in den Datenstrom eingefügt.
- Leseoperationen mittels ReadLn liefern in diesem Fall auch nur
- diejenigen Zeichen, die bis zu einem solchen Trenner gefunden werden.
-
- Beispiel: VAR Ziel : String[85];
- N : Byte;
-
- For N := 1 TO 5 DO
- WriteLn(Pipe,'Dies ist ein Test');
- ReadLn(Pipe,Ziel);
- Writeln(Ziel);
-
- In diesem Fall wird genau eine Zeile "Dies ist ein Test" aus der
- Pipe gelesen und angezeigt.
-
-
- Kontrollierte Endeabläufe schaffen
-
- Soll eine Kommunikationsverbindung über eine Pipe in der laufenden
- Anwendung vollständig abgebaut werden, so ist darauf zu achten, daß
- nach Möglichkeit jeweils derjenige Prozeß, der einen Open auf die
- Pipe abgesetzt hat, auch den jeweiligen Close ausführt. Unter allen
- Umständen muß verhindert werden, daß zu einem Zeitpunkt, zu dem noch
- Read/Write-Aufträge auf eine Dateivariable aktiv sind, diese durch
- einen anderen Prozeß geschlossen wird.
-
- Beispiel: Die Unit V24Pipe definiert zwei Pipes, die über die globalen
- Dateivariablen AuxIn und AuxOut angesprochen werden können.
- Beide Pipes werden nicht von der Anwendung, sondern von
- einer Routine dieser Unit eröffnet und bereitgestellt.
- Auch für das Schließen dieser Pipes und den Abbau der Ver-
- bindung zur Schnittstelle, ist eine interne Prozedur
- verantwortlich.
- Es wäre nun denkbar, daß zum Zeitpunkt des Aufrufes dieser
- Prozedur noch eine Eingabe-Task auf Daten von der Pipe
- AuxIn wartet (von der Schnittstelle), jedoch mangels
- Eingaben blockiert ist.
-
- Wird in dieser Situation die Pipe AuxIn einfach geschlossen, kann es
- zu sehr unschönen Erscheinungen kommen. Die harmloseste Form wäre
- eine Eingabe-Task, die auf immer blockiert ist, da sie auf eine
- nicht mehr vorhandene Semaphore wartet. Den schlimmsten Fall
- jedoch, stellt eine Situation dar, in der die Eingabe-Task reakti-
- viert wird, jedoch erst nach Löschung der Pipe wieder CPU-Zeit
- erhält. Sie wird dann auf Datenstrukturen zugreifen, die nicht mehr
- vorhanden sind, und u. U. die Struktur des Heap zerstören!!!!!
- (Nur am Rande sei an dieser Stelle bemerkt, daß das soeben geschil-
- derte Problem von der Unit V24Pipe entsprechend behandelt wird).
-
- Wichtig zu wissen ist, daß auch die ständige Abfrage mittels
- IOResult auf einen evtl. Fehler beim Lesezugriff, die Eingabe-Task
- aus dem gerade erwähnten Beispiel nicht rettet!! IoResult hat die
- im Hinblick auf Multi-Tasking unangenehme Eigenschaft, den
- Fehlerstatus nach jedem Aufruf zurückzusetzen. Sind also mehrere
- Tasks im Hinblick auf ihre Beendigung von einem I/O-Fehler bzgl.
- einer bestimmten Pipe abhängig, so wird nur eine von ihnen den Fehler
- registrieren. Die andere erhält beim Aufruf von IOResult den Wert 0,
- da ja der Fehler bereits abgerufen wurde.
-
- Im Regelfall steht bereits beim Entwurf der Kommunikation fest,
- welche Task durch einen Zugriffsfehler auf eine Endebedingung
- aufmerksam gemacht wird. Nur diese wird dann auch die
- IOResult-Abfrage enthalten, da im Hinblick auf Pipes ja nur in einer
- ganz spezifischen Situation ein Zugriffsfehler generiert wird. Das
- Programm FINDER soll als anschauliches Beispiel für den Normalfall
- einer Pipe-Kommunikation dienen.
-
- Registrierte Benutzer, die von diesem Standardfall abweichen
- möchten und u. U. mit o. g. Problemen konfrontiert werden, sollten
- sich den Quellcode der Units MtPrint und V24Pipe ein wenig genauer
- anschauen.
- Der Neustart des Spoolers in MtPrint ist z. B. mit einem Abbau der
- Pipe Lst verbunden und wird über Semaphoren synchronisiert.
- Dies ist ein sehr sicherer Weg, den ich Ihnen als Muster nur
- empfehlen kann.
- Etwas weniger klar ist der Ablauf in der Unit V24Pipe, die mit einem
- noch viel komplizierteren Verbindungsabbau fertig werden muß. Dort
- existieren zwei Pipes und zwei Hintergrundprozesse, von denen einer
- auch noch von externen Ereignissen abhängig ist. Dort habe ich auch
- zu ziemlich radikalen Mitteln gegriffen, um einen sauberen Abbau der
- Verbindung sicherzustellen. Wann immer es möglich ist, sollte auf
- derartige Verfahren verzichtet werden; wo es unvermeidlich ist, kann
- V24Pipe als Beispiel sehr nützlich sein.
-
-
- Pipes und Kill()
-
- Tasks, die Pipe-Zugriff ausführen, sollten nicht mittels Kill() aus
- dem System entfernt werden, da dies in seltenen Fällen zu Problemen
- bei weiteren Zugriffen auf die betreffende Pipe führen kann.