home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / pascal / library / dos / multtsk / cpmult / doku / mtpipe.dok < prev    next >
Encoding:
Text File  |  1990-04-23  |  24.4 KB  |  556 lines

  1. .. //////////////////////////////////////////////////////////////////
  2. .. /// Dokumentation zum Multi-Tasking Subsystem V2.10 / April 1990
  3. .. /// Modul MTPIPE
  4. .. /// Format: DOCLIST 1.00-Format
  5. .. //////////////////////////////////////////////////////////////////
  6. .. /// Bitte passen Sie die nachfolgenden Zeile ggf. für Ihren
  7. .. /// Drucker an. Die Voreinstellung paßt auf einen EPSON FX-85
  8. .. /// mit Papierformat 12"
  9. .. //////////////////////////////////////////////////////////////////
  10. .PL 72      Seitenlänge 72 Zeilen
  11. .LL 80      Zeilenlänge 80 Zeichen
  12. .ID 5       Einrücken um 5 Zeichen vom linken Rand
  13. .RM 5       5 Zeichen bis zum rechten Rand Platz lassen -> 70
  14. ..          Zeichen Text je Zeile
  15. .HS =       Zeichen für Kopf-/Fuß-Trenner
  16. .RS -       Zeichen für Trennung von Referenz-Einträgen
  17. .CO (c) Copyright 1988..1990 Ch.Philipps Software-Technik
  18. .. //////////////////////////////////////////////////////////////////
  19. .SE Multi-Tasking Subsystem für Turbo-Pascal 5.x Version 2.10
  20.  
  21.  
  22.  
  23.  
  24.  
  25.  
  26.  
  27.  
  28.             Turbo Pascal 5.x  Multi-Tasking Subsystem
  29.  
  30.  
  31.                     MTPIPE - Benutzerhandbuch
  32.  
  33.  
  34.  
  35.  
  36.  
  37.  
  38.  
  39.  
  40.                  (c) Copyright 1988, 1989, 1990
  41.  
  42.                Christian Philipps Software-Technik
  43.  
  44.                      alle Rechte vorbehalten
  45.  
  46.  
  47.                    Version 2.10  / April 1990
  48.  
  49.  
  50.  
  51.  
  52.  
  53.  
  54.  
  55.  
  56.  
  57.  
  58.  
  59.  
  60.          Anschrift:  Christian Philipps
  61.                      Software-Technik
  62.                      Düsseldorfer Str. 316
  63.  
  64.                      D-4130 Moers 1
  65.  
  66.          Telefon..:  02841 / 35932
  67.          Fido-Netz:  509/3.4
  68.  
  69. .SE Lizenzvereinbarung, Garantie- und Haftungsausschluß, Warenzeichen
  70. siehe hierzu CPMULTI.DOK
  71. .SE MTPIPE / Leistungsbeschreibung
  72. 1. Leistungsbeschreibung
  73.  
  74. Die Zusatzunit MTPipe beinhaltet einen Turbo Pascal Textdatei-
  75. Gerätetreiber für die Verwaltung von "Named Pipes". 
  76.  
  77. Es können dem zur Verfügung stehenden Heap-Space entsprechend viele 
  78. Pipes angelegt werden, auf die konkurrierend mit mehreren Tasks 
  79. schreibend bzw. lesend zugegriffen werden kann.
  80.  
  81. Der Datenaustausch über die Pipe erfolgt mittels der Standard Pascal 
  82. Prozeduren Read/Readln bzw. Write/Writeln, wobei die Pipe wie eine
  83. Textdatei behandelt wird. Evtl. auftretende Fehler können mittels 
  84. IOResult behandelt werden.
  85.  
  86. Der Pipe-Treiber sorgt allein für die Synchronisation des Daten-
  87. transfers, wodurch die Pipe zu einem sehr einfach zu benutzenden
  88. Kommunikationsmedium wird.
  89.  
  90.  
  91. Hinweis für registrierte Anwender des Multi-Tasking Subsystems
  92. --------------------------------------------------------------
  93.  
  94. Bitte beachten Sie, daß für diese Unit gleichfalls die Lizenzver-
  95. einbarungen gelten, die in der Dokumentation zum Multi-Tasking Sub-
  96. system aufgeführt sind.
  97. Insbesondere bedeutet dies, daß Sie die lizenzierte Version dieses
  98. Produktes, seine Dokumentation und seinen Quellcode unter keinen
  99. Umständen an Dritte weitergeben dürfen, weder auszugsweise, noch
  100. vollständig. Diese Unit einschließnlich ihrer Dokumentation ist, wie
  101. auch CPMulti, in der lizenzierten Version KEINE ShareWare, sondern
  102. ausschließlich gemäß den Lizenzvereinbarungen (siehe CPMULTI.DOK) zu
  103. behandeln.
  104. .SE MTPIPE / Einbindung der Unit
  105. 2. Einbindung der Unit in eigene Programme
  106.  
  107. Wie beim Multi-Tasking-Subsystem selbst, gestaltet sich auch hier die
  108. Einbindung unproblematisch. Durch einen entsprechenden Eintrag in der
  109. USES-Klausel Ihres Programmes, wird MtPipe integriert. Beim Start
  110. des Anwendungsprogrammes initialisiert sich MtPipe selbst.
  111.  
  112. Beispiel:  USES CPMULTI, MtPipe;
  113.  
  114. Bitte beachten Sie die Reihenfolge der Einbindung, die in Kapitel 8
  115. des Handbuches zu CpMulti angegeben ist.
  116. .SE MTPIPE / Konzept
  117. 3. Konzept
  118.  
  119. Eine Pipe bildet einen Einweg-Kommunikationskanal zwischen zwei 
  120. Prozessen. Bezogen auf zwei Kommunikationspartner, ist stets ein 
  121. Partner der Schreibende und der andere Partner der Lesende. Niemals
  122. kann ein Prozeß gleichzeitig in eine Pipe schreiben und auch wieder 
  123. aus ihr lesen.
  124.  
  125. Eine Pipe wird mittels einer speziellen Assign Prozedur (Assign-
  126. Pipe), ähnlich der Standard-Prozedur Assign einer Dateivariablen vom 
  127. Typ "Text" zugeordnet und kann anschließend mittels Reset, Rewrite 
  128. oder Append lesend bzw. schreibend eröffnet werden. Zu beachten ist 
  129. hierbei, daß im Gegensatz zu Dateien, der Inhalt der Pipe durch 
  130. Rewrite nicht gelöscht wird. Rewrite und Append verhalten sich im 
  131. Hinblick auf die Pipe funktionsgleich.
  132.  
  133. Jede Task, die eine Pipe eröffnen möchte, benötigt hierzu eine
  134. EIGENE Dateivariable vom Typ "Text". Kommunizieren z. B. 5 Tasks
  135. miteinander über eine Pipe, so existieren für diese Pipe 5 eröffnete
  136. Dateivariablen, die jedoch auf ein und dieselbe Pipe verweisen. Wie
  137. wird dies bewerkstelligt?
  138.  
  139. Ähnlich der Standardprozedur "Assign", existiert für Pipes eine
  140. spezielle Funktion mit Namen "AssignPipe" deren Aufgabe es ist, die
  141. Verbindung zwischen einer Dateivariablen und den internen Daten-
  142. strukturen einer Pipe herzustellen.
  143. Beim Assign wird der Pipe ein Name gegeben, der im System eindeutig
  144. sein muß. Über diesen Namen können sich später andere Prozesse an
  145. eine bereits bestehende Pipe "anhängen". Eine Pipe wird automatisch 
  146. erzeugt, wenn ein Prozeß einen Assign-Aufruf mit einem Pipe-Namen 
  147. absetzt, der im System noch nicht vorhanden ist. Ist zum Zeitpunkt 
  148. des Assign bereits eine Pipe mit dem angegebenen Namen vorhanden, so 
  149. wird der anfordernde Prozeß an diese angeschlossen.
  150.  
  151. Nach erfolgreichem Öffnen der Pipe, können Daten mittels Write oder 
  152. Writeln in diese geschrieben werden (eröffnet mit Rewrite oder 
  153. Append) bzw. mittels Read oder Readln aus dieser gelesen werden 
  154. (eröffnet mit Reset). Bitte lesen Sie den Abschnitt 7 (Programmier-
  155. hinweise) dieser Dokumentation gründlich, bevor Sie die ersten Ver-
  156. suche mit Pipes starten. Auch das Studium des Demoprogrammes FINDER
  157. ist sehr sinnvoll.
  158.  
  159. Die Datenspeicherung innerhalb der Pipe erfolgt in einem Ringpuffer, 
  160. dessen Größe beim Erzeugen der Pipe festgelegt wird und der 
  161. dynamisch auf dem Heap zugewiesen wird. Der Zugriff auf diesen 
  162. Ringpuffer wird, für die Kommunikationspartner unsichtbar, über 
  163. Semaphoren synchronisiert.
  164. Wann immer ein Prozeß aus einer Pipe lesen möchte, die keine Daten
  165. enthält, wird er bis zum Eintreffen von Daten blockiert.
  166. Andererseits wird ein Schreiber blockiert, wenn nicht ausreichen
  167. Platz in der Pipe vorhanden ist, um seine gesamten Daten aufzunehmen.
  168.  
  169. Zu jedem Zeitpunkt können theoretisch mehrere lesende und mehrere 
  170. schreibende Prozesse gleichzeitig Zugriff auf eine Pipe ausüben. 
  171. Praktisch sinnvoll ist in der Regel jedoch nur die Kombination 
  172. mehrerer schreibender Prozesse mit einem Leser (siehe FINDER).
  173.  
  174. Im Normalfall werden zu einer Pipe immer mindestens zwei Prozesse
  175. existieren, die diese Pipe als Kommunikationskanal nutzen. Einer
  176. füllt die Pipe mit Daten; der Andere entnimmt diese wieder und ver-
  177. arbeitet sie weiter.
  178. Sehr häufig wird irgendwann einmal ein Punkt erreicht, an dem der
  179. schreibende Prozeß seine Aufgabe beendet hat und keine weiteren
  180. Daten mehr liefert. Normalerweise wird er seine Seite der Pipe
  181. schließen und sich beenden oder andere Aufgaben wahrnehmen. Ohne
  182. besondere Vorkehrungen, würde dies für den lesenden Prozeß bedeuten,
  183. daß dieser blockiert würde, sobald er alle Daten aus der Pipe
  184. verarbeitet hat und in diesem Zustand für den Rest seines Lebens
  185. handlungsunfähig verbleiben müßte.
  186. Dies ist offensichtlich nicht wünschenswert. Vielmehr wäre es
  187. sinnvoll, den Leser mittels eines geeigneten Signals darauf
  188. hinzuweisen, daß keine Gegenstelle mehr existiert. Es wäre z. B.
  189. praktisch, in diesem Fall eine EOF-Bedingung zu erzeugen. Aus
  190. technischen Gründen hat sich diese Möglichkeit in Verbindung mit
  191. TEXT-Dateien nicht bewährt. Dies liegt in der internen Struktur der
  192. EOF-Funktion von Turbo Pascal begründet und soll hier nicht näher
  193. diskutiert werden.
  194. Der Pipe-Treiber liefert im Falle von Schreibzugriffen auf eine
  195. Pipe, zu der kein weiterer Prozeß Zugang hat, den Fehler 101
  196. (Platten-Schreibfehler) und bei Lesezugriffen auf eine Pipe ohne
  197. Gegenstelle den Fehler 100 (Platten-Lesefehler). An Stellen, an
  198. denen die o. g. Situation auftreten kann, muß nach jedem Zugriff auf
  199. die Pipe mittels IOResult der Fehlerstatus abgefragt werden!! Auch
  200. setzt dies voraus, daß der Compiler-Schalter I- gesetzt ist.
  201.  
  202. Lassen Sie mich nun den Faden noch einmal weiterspinnen: Es ist
  203. durchaus denkbar, daß der lesende Prozeß eine höhere Priorität
  204. besitzt als der Schreiber. In diesem Fall wird er stets die gesamte
  205. Pipe entleeren und beim folgenden Lesezugriff blockiert. Erst dann
  206. kommt der Schreiber wieder zum Zuge, um neue Daten in die Pipe zu
  207. schreiben. Es ist nun sehr wahrscheinlich, daß der Leser bereits
  208. wieder im Zustand der Blockierung auf Daten wartet, wenn der
  209. Schreiber seine Seite der Pipe schließt, da er keine weiteren Daten
  210. zu liefern hat. In diesem Fall wird der "schlafende" Leser
  211. reaktiviert und erhält die Fehlermeldung 100. Gleiches geschieht,
  212. wenn ein schreibender Prozeß auf Freispeicher in der Pipe wartet und
  213. die Gegenstelle ihre Seite der Pipe schließt; der Schreiber erhält
  214. wiederum den Fehler 101.
  215.  
  216. Die letzten Abschnitte gehören genaugenommen bereits in das Kapitel
  217. "Realisierung". Ich habe sie jedoch bewußt vorgezogen, um denjenigen
  218. Anwendern, die die Datails des Treibers nicht weiter interessieren,
  219. das Studium des Kaptitels 4 ersparen zu können.
  220. Wenn Ihnen nur an der Anwendung der Unit gelegen ist, so können Sie
  221. nun getrost zum Kapitel 5 übergehen.
  222. .SE MTPIPE / Realisierung
  223. 4. Realisierung
  224.  
  225. Die Unit DOS definiert einen Record namens "TextRec", der das wesent-
  226. liche Bindeglied zwischen einem TEXT-Datei Treiber und den Standard-
  227. Funktionen/Prozeduren zur Dateiein-/ausgabe herstellt.
  228. Dieser Record ist im zweiten Band Ihres Turbo Pascal Handbuches
  229. ausführlich beschrieben. Strukturell verbirgt sich hinter dem
  230. Dateityp "Text" nichts anderes, als eben dieser "TextRec". Im
  231. Folgenden verwende ich daher die Begriffe "Dateivariable" und
  232. "TextRec" als Synonyme.
  233.  
  234. Wie bereits erwähnt, existiert für jede Verbindung zu einer Pipe eine
  235. separate Dateivariable vom Tpy "Text". Diese enthält u. a. einen
  236. Default-Puffer mit einer Größe von 128 Bytes sowie Felder, in denen
  237. der Modus (Lesend/Schreibend) sowie der Füllstand des Puffers
  238. abgelegt werden. Weiterhin ist auch ein Bereich für den mit dieser
  239. Dateivariablen verbundene Dateinamen vorgesehen.
  240.  
  241. Die Verbindung zwischen einem TEXT-Datei Gerätetreiber und der
  242. Dateivariablen wird über eine Reihe von Pointerfeldern im "TextRec"
  243. hergestellt, die auf die Treiberroutinen zum Öffnen, Schließen
  244. und Datentransfer verweisen. Die Adressen dieser Routinen müssen
  245. dort von der Assign-Routine bzw. der Open-Routine des Treibers
  246. hinterlegt werden.
  247.  
  248. Neben den festen Bestandteilen existiert noch ein Feld "UserData",
  249. welches der Programmierer eigener Gerätedateitreiber redefinieren und
  250. nach Belieben verwenden kann. Der Pipe-Treiber verwendet dieses Feld
  251. in erster Linie dazu, eine Verbindung zwischen den einzelnen
  252. Dateivariablen der Kommunikationspartner und den internen
  253. Datenstrukturen der Pipe herzustellen.
  254.  
  255. Bildhaft könnte man sich dies wiefolgt vorstellen:
  256.  
  257.  
  258.   ┌───────────────────┐
  259.   │Task 1 (schreibend)│
  260.   │                   │
  261.   │                   │
  262.   │VAR SPipe : TEXT   │
  263.   └──────┬────────────┘
  264.          │
  265.          │
  266.   ┌──────┴───────────┐                ┌─────────────────┐
  267.   │Pipe-Verwaltungs- ├────────────────┤Pipe-Datenbereich│
  268.   │struktur          │                │                 │
  269.   └──────┬───────────┘                │                 │
  270.          │                            │                 │
  271.          │                            │                 │
  272.   ┌──────┴────────────┐               │                 │
  273.   │VAR LPipe : TEXT   │               │                 │
  274.   │                   │               │                 │
  275.   │                   │               │                 │
  276.   │Task 2 (lesend)    │               └─────────────────┘
  277.   └───────────────────┘
  278.  
  279.  
  280. Die Pipe-Verwaltungsstrukturen aller im System befindlichen Pipes
  281. werden mittels der Unit Queue in Form einer doppelt verketteten
  282. Liste verwaltet. Ein Zeiger auf den zugehörigen Verwaltungssatz wird
  283. in jeder angeschlossenen Dateivariablen (im Feld UserData) hinterlegt.
  284.  
  285. Der Verwaltungssatz enthält u. a. ein Namensfeld, dessen Inhalt als
  286. identifizierendes Merkmal verwendet wird, einen Zeiger auf den
  287. Datenbereich der Pipe sowie fünf Semaphoren, die den Zugriff auf die
  288. Pipe synchronisieren. Die Anzahl der aktuell eröffneten Kommunika-
  289. tionskanäle zu einer Pipe werden in einem Zählfeld verwaltet. Anhand
  290. dieses Zählers kann der Treiber feststellen, ob zum Zeitpunkt eines
  291. Zugriffs auf die Pipe noch weitere Kommunikationspartner existieren.
  292. Der Rest des Verwaltungssatzes wird für die Überwachung des
  293. Datenbereiches (Füllstand, etc.) benötigt.
  294.  
  295. Der für den Verwaltungssatz und den Datenbereich der Pipe benötgte
  296. Speicherplatz wird auf dem Heap reserviert. Ist nicht ausreichend
  297. Speicher vorhanden, so liefert die Assign-Funktion einen Fehler
  298. zurück.
  299.  
  300. Sobald der letzte Kommunikationspartner die Pipe geschlossen hat,
  301. wird diese aus dem System entfernt; der dynamisch angelegte Speicher
  302. wird wieder freigegeben.
  303. .SE MTPIPE / Exportierte Typdefinitionen
  304. 5. Exportierte Typdefinitionen
  305.  
  306. PipeNameType = String[8]; 
  307. .SE MTPIPE / Referenz
  308. 6. Funktionsbeschreibung (alphabetisch)
  309.  
  310.  
  311. .RE AssignPipe
  312. Deklaration
  313.  
  314.   FUNCTION AssignPipe(VAR PT:Text; PName:PipeNameType; PSize:Word;
  315.               RequestSize:Byte; AlwaysBlock:WaitFlagType):BOOLEAN;
  316.  
  317. Funktion
  318.  
  319.   Erzeugen einer Pipe bzw. Anmelden an eine bereits vorhandene Pipe.
  320.   Der erste Parameter "PT" bezeichnte die TEXT-Dateivariable, über
  321.   die die Kommunikation mit der Pipe stattfinden soll. JEDE Task,
  322.   die auf eine Pipe zugreift, besitzt eine EIGENE Dateivariable!!!
  323.   "PName" enthält den Namen, unter dem die Pipe im System bekannt
  324.   ist. Existiert diese Pipe bereits, so wird der aufrufende Prozeß
  325.   mit dieser verbunden. In diesem Fall ist der Parameter "PSize"
  326.   ohne Belang.
  327.   Ist unter dem angegebenen Namen (Groß- und Kleinschreibung werden
  328.   unterschieden!!!!!) noch keine Pipe im System vorhanden, so wird
  329.   sie mit einem Datenbereich in der Größe "PSize" angelegt. "PSize"
  330.   muß in diesem Fall MINDESTENS 128 betragen.
  331.   Der Parameter "RequestSize" gibt an, wieviele Zeichen auf einmal
  332.   zwischen dem Puffer der Dateivariablen und dem Datenbereich der
  333.   Pipe hin und her übertragen werden. Ist dieser Wert 0, so wird
  334.   standardmäßig der Wert 128 (entsprechend der Größe des Puffers der
  335.   Dateivariablen) eingesetzt. Dies ist auch der maximal zulässige
  336.   Wert für diesen Parameter.
  337.   Der letzte Parameter, "AlwaysBlock", kann die Werte "Wait" und
  338.   "NoWait" annehmen. Diese Angabe bezieht sich auf das Verhalten
  339.   eine Task wenn sie auf eine Pipe zugreift, zu der keine
  340.   Gegenstelle mehr vorhanden ist. "NoWait" bewirkt die sofortige
  341.   Rückkehr mit einem Fehlercode (100/101). "Wait" bewirkt, daß die
  342.   Task blockiert wird und solange blockiert bleibt, bis eine
  343.   Gegenstelle existiert und sie durch Füllen/Leeren der Pipe
  344.   reaktiviert.
  345.  
  346.   ACHTUNG!!!!
  347.   Unabhängig vom Parameter "AlwaysBlock", wird eine Task mit einem
  348.   Fehler reaktiviert, falls sie gerade blockiert ist, wenn der letzte
  349.   Kommunikationspartner seine Seite der Pipe schließt!!
  350.  
  351.   AssignPipe liefert den Wert TRUE, wenn die Aktion erfolgreich
  352.   durchgeführt werden konnte. Im Fehlerfall wird FALSE geliefert.
  353.   Fehler deuten auf eine falsche Angabe in "PSize" hin oder darauf,
  354.   daß nicht ausreichen Heap-Space zur Verfügung stand.
  355.  
  356. Beispiel
  357.  
  358.      .......
  359.  
  360.   IF NOT AssignPipe(Lst,'MtPrinter',0,1,NoWait)
  361.      THEN MtPrintError(ErrAsgn)
  362.      ELSE Reset(Lst);
  363.  
  364.      .......
  365.  
  366. Kommentar
  367.  
  368.   Der Parameter "RequestSize" ist in der Mehrzahl der Fälle
  369.   vollkommen ohne Belang, da er lediglich den internen Datentransfer
  370.   zwischen TEXT-Record und Pipe regelt. Der Anwender bekommt diese
  371.   automatisch ablaufenden Vorgänge nicht mit.
  372.   Kleinere Werte als die Standardgröße von 128 Bytes bewirken
  373.   normalerweise nur eine Verschlechterung der Performance, da mehr
  374.   Aufrufe der Treiber-Funktionen erforderlich werden, um die gleiche
  375.   Menge an Daten zu transportieren.
  376.   Zuweilen jedoch, z. B. im Print-Spooler, kann es wichtig sein, die
  377.   maximal bei jedem Aufruf transferierte Zeichenmenge zu begrenzen.
  378.   Der Print-Spooler, der ja performance-unkritisch im Hintergrund
  379.   Zeichen zum Drucker schickt, setzt diese Grenze auf 1 Byte herab.
  380.   Dadurch kann der Druckoutput nach jedem Zeichen bei Bedarf ge-
  381.   cancelled werden.
  382.  
  383.   Noch ein Wort zur "RequestSize". Wie bereits erwähnt, ist der
  384.   Maximalwert für die RequestSize 128. Für Textdateien existiert die
  385.   Prozedur SetTextBuf, die es erlaubt, einen größeren Übertragungs-
  386.   puffer zur Verfügung zu stellen. Dies hilft bei der Übertragung
  387.   großer Datenmengen, die Anzahl Plattenzugriffe zu reduzieren.
  388.   SetTextBuf ist auch auf Pipes anwendbar, wenngleich sie dort,
  389.   aufgrund fehlender Plattenzugriffe, nicht allzuviel Sinn macht.
  390.   Möchten Sie einen größeren Puffer und somit einen größeren Wert
  391.   für RequestSize (>128) verwenden, so ist SetTextBuf NACH dem
  392.   Aufruf von AssignPipe, jedoch VOR dem Aufruf von Reset/Rewrite/
  393.   Append auf die Dateivariable anzuwenden. RequestSize wird dadurch
  394.   automatisch auf die Größe des von Ihnen angegebenen Puffers erhöht.
  395. .EE
  396. ────────────────────────────────────────────────────────────────────
  397. .RE ExistPipe
  398. Deklaration
  399.  
  400.   FUNCTION ExistPipe(PName:PipeNameType):BOOLEAN;
  401.  
  402. Funktion
  403.  
  404.   Prüfe, ob bereits eine Pipe unter dem angegebenen Namen existiert.
  405.   Dies kann u. U. nützlich sein, wenn ein Prozess nur die Pipe lesen
  406.   möchte. Durch den Assign würde diese jedoch bereits physisch angelegt,
  407.   was aber nicht immer wünschenswert ist.
  408. .SE MTPIPE / Programmierhinweise
  409. 7. Programmierhinweise
  410.  
  411. Größenangaben
  412.  
  413. Versuche, eine Pipe mit einer Puffergröße (PSize) < 128 Bytes
  414. anzulegen, führen beim Assign zu einem Fehler. Diese Aussage bezieht
  415. sich nur auf einen Assign-Befehl für eine noch nicht vorhandene
  416. Pipe. Ist unter dem angegebenen Namen bereits eine Pipe aktiv, so
  417. wird der Parameter PSize nicht beachtet.
  418.  
  419.  
  420. Read/ReadLn und Write/Writeln
  421.  
  422. Mit den o. a. Prozeduren lassen sich sowohl Strings als auch
  423. Einzelzeichen (CHAR) und numerische Daten über Pipes austauschen. Es
  424. ist jedoch zu beachten, daß der Empfänger lediglich mit einem
  425. unstrukturierten Datenstrom einzelner Bytes konfrontiert wird, d. h.
  426. im Normalfall nicht zwischen diesen Datentypen unterscheiden kann.
  427. Dem Empfänger muß also bekannt sein, welche Datentypen er in welcher
  428. Reihenfolge in er Pipe erwarten kann. Das Programm FINDER kann als
  429. gutes Beispiel für den gemischten Austausch verschiedener Datentypen
  430. über eine Pipe dienen.
  431.  
  432. Im Hinblick auf numerische Datentypen, verhält sich die Pipe ähnlich
  433. der Tastatur bei der normalen Eingabe mittels Read.
  434.  
  435. Beispiel: Read(NumVar) --> Eingabe: 1234a  --> Fehler 106 (ungülti-
  436.                                                ges Zahlenformat)
  437. dagegen.: Read(NumVar) --> Eingabe: 1234 a --> 1234 wird erkannt
  438.  
  439. Ein numerisches Datum muß also durch mindestens eine Leestelle von den
  440. nachfolgenden Daten getrennt werden. Das oder die Leerzeichen
  441. verbleiben allerdings in der Pipe und werden dem nachfolgenden Datum
  442. zugerechnet.
  443.  
  444. Strings sollten möglichst mittels WriteLn in die Pipe geschrieben
  445. und mittels ReadLn aus dieser gelesen werden. Der Grund für diese
  446. Empfehlung ist, daß Strings nur in ihrer tatsächlichen Länge
  447. geschrieben werden, jedoch die Prozedur Read versucht, die dem
  448. Zieldatentyp (Zielstring) entsprechende Maximalanzahl von Zeichen zu
  449. lesen.
  450.  
  451. Beispiel: VAR Ziel : String[85];
  452.               N    : Byte;
  453.  
  454.           For N := 1 TO 5 DO
  455.             Write(Pipe,'Dies ist ein Test');
  456.           Read(Pipe,Ziel);
  457.           Writeln(Ziel);
  458.  
  459. Als Ergebnis würden auf dem Bildschirm die fünf Quellstrings
  460. unmittelbar hintereinander, d. h. ohne jegliches Trennzeichen,
  461. ausgegeben. Read hat keinerlei Möglichkeit festzustellen, daß sich
  462. die Quelldaten aus fünf Einzelstrings à 17 Zeichen zusammensetzen
  463. und füllt daher den Zielpuffer in seiner maximalen Länge.
  464.  
  465. Im Gegensatz dazu, wird durch Verwendung von WriteLn für Strings ein
  466. Zeilenende-Zeichen explizit in den Datenstrom eingefügt.
  467. Leseoperationen mittels ReadLn liefern in diesem Fall auch nur
  468. diejenigen Zeichen, die bis zu einem solchen Trenner gefunden werden.
  469.  
  470. Beispiel: VAR Ziel : String[85];
  471.               N    : Byte;
  472.  
  473.           For N := 1 TO 5 DO
  474.             WriteLn(Pipe,'Dies ist ein Test');
  475.           ReadLn(Pipe,Ziel);
  476.           Writeln(Ziel);
  477.  
  478. In diesem Fall wird genau eine Zeile "Dies ist ein Test" aus der
  479. Pipe gelesen und angezeigt.
  480.  
  481.  
  482. Kontrollierte Endeabläufe schaffen
  483.  
  484. Soll eine Kommunikationsverbindung über eine Pipe in der laufenden
  485. Anwendung vollständig abgebaut werden, so ist darauf zu achten, daß
  486. nach Möglichkeit jeweils derjenige Prozeß, der einen Open auf die
  487. Pipe abgesetzt hat, auch den jeweiligen Close ausführt. Unter allen
  488. Umständen muß verhindert werden, daß zu einem Zeitpunkt, zu dem noch
  489. Read/Write-Aufträge auf eine Dateivariable aktiv sind, diese durch
  490. einen anderen Prozeß geschlossen wird.
  491.  
  492. Beispiel: Die Unit V24Pipe definiert zwei Pipes, die über die globalen
  493.           Dateivariablen AuxIn und AuxOut angesprochen werden können.
  494.           Beide Pipes werden nicht von der Anwendung, sondern von
  495.           einer Routine dieser Unit eröffnet und bereitgestellt.
  496.           Auch für das Schließen dieser Pipes und den Abbau der Ver-
  497.           bindung zur Schnittstelle, ist eine interne Prozedur
  498.           verantwortlich.
  499.           Es wäre nun denkbar, daß zum Zeitpunkt des Aufrufes dieser
  500.           Prozedur noch eine Eingabe-Task auf Daten von der Pipe
  501.           AuxIn wartet (von der Schnittstelle), jedoch mangels
  502.           Eingaben blockiert ist.
  503.  
  504. Wird in dieser Situation die Pipe AuxIn einfach geschlossen, kann es
  505. zu sehr unschönen Erscheinungen kommen. Die harmloseste Form wäre
  506. eine Eingabe-Task, die auf immer blockiert ist, da sie auf eine
  507. nicht mehr vorhandene Semaphore wartet. Den schlimmsten Fall
  508. jedoch, stellt eine Situation dar, in der die Eingabe-Task reakti-
  509. viert wird, jedoch erst nach Löschung der Pipe wieder CPU-Zeit
  510. erhält. Sie wird dann auf Datenstrukturen zugreifen, die nicht mehr
  511. vorhanden sind, und u. U. die Struktur des Heap zerstören!!!!!
  512. (Nur am Rande sei an dieser Stelle bemerkt, daß das soeben geschil-
  513. derte Problem von der Unit V24Pipe entsprechend behandelt wird).
  514.  
  515. Wichtig zu wissen ist, daß auch die ständige Abfrage mittels
  516. IOResult auf einen evtl. Fehler beim Lesezugriff, die Eingabe-Task
  517. aus dem gerade erwähnten Beispiel nicht rettet!! IoResult hat die
  518. im Hinblick auf Multi-Tasking unangenehme Eigenschaft, den
  519. Fehlerstatus nach jedem Aufruf zurückzusetzen. Sind also mehrere
  520. Tasks im Hinblick auf ihre Beendigung von einem I/O-Fehler bzgl.
  521. einer bestimmten Pipe abhängig, so wird nur eine von ihnen den Fehler
  522. registrieren. Die andere erhält beim Aufruf von IOResult den Wert 0,
  523. da ja der Fehler bereits abgerufen wurde.
  524.  
  525. Im Regelfall steht bereits beim Entwurf der Kommunikation fest,
  526. welche Task durch einen Zugriffsfehler auf eine Endebedingung
  527. aufmerksam gemacht wird. Nur diese wird dann auch die
  528. IOResult-Abfrage enthalten, da im Hinblick auf Pipes ja nur in einer
  529. ganz spezifischen Situation ein Zugriffsfehler generiert wird. Das
  530. Programm FINDER soll als anschauliches Beispiel für den Normalfall
  531. einer Pipe-Kommunikation dienen.
  532.  
  533. Registrierte Benutzer, die von diesem Standardfall abweichen
  534. möchten und u. U. mit o. g. Problemen konfrontiert werden, sollten
  535. sich den Quellcode der Units MtPrint und V24Pipe ein wenig genauer
  536. anschauen.
  537. Der Neustart des Spoolers in MtPrint ist z. B. mit einem Abbau der
  538. Pipe Lst verbunden und wird über Semaphoren synchronisiert.
  539. Dies ist ein sehr sicherer Weg, den ich Ihnen als Muster nur
  540. empfehlen kann.
  541. Etwas weniger klar ist der Ablauf in der Unit V24Pipe, die mit einem
  542. noch viel komplizierteren Verbindungsabbau fertig werden muß. Dort
  543. existieren zwei Pipes und zwei Hintergrundprozesse, von denen einer
  544. auch noch von externen Ereignissen abhängig ist. Dort habe ich auch
  545. zu ziemlich radikalen Mitteln gegriffen, um einen sauberen Abbau der
  546. Verbindung sicherzustellen. Wann immer es möglich ist, sollte auf
  547. derartige Verfahren verzichtet werden; wo es unvermeidlich ist, kann
  548. V24Pipe als Beispiel sehr nützlich sein.
  549.  
  550.  
  551. Pipes und Kill()
  552.  
  553. Tasks, die Pipe-Zugriff ausführen, sollten nicht mittels Kill() aus
  554. dem System entfernt werden, da dies in seltenen Fällen zu Problemen
  555. bei weiteren Zugriffen auf die betreffende Pipe führen kann.
  556.