home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PASCAL / MULTSKTP.ZIP / QUEUE.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1988-08-20  |  10.9 KB  |  303 lines

  1. {//////////////////////////////////////////////////////////////////////////////
  2. ///                                                                         ///
  3. ///           Universelle Verwaltung einfach verketteter Listen             ///
  4. ///                                                                         ///
  5. ///                 (c) Christian Philipps, Moers                           ///
  6. ///                         im Juli 1988                                    ///
  7. ///                                                                         ///
  8. ///              Dieses System erfordert Turbo-Pascal V4.0                  ///
  9. ///              und die Unit TP4MULTI                                      ///
  10. ///                                                                         ///
  11. //////////////////////////////////////////////////////////////////////////////}
  12.  
  13. {$R-,S-,I-,D-,T-,F-,V-,B-,N-,L+ }
  14.  
  15. UNIT Queue;
  16.  
  17. INTERFACE
  18.  
  19. USES Tp4Multi;
  20.  
  21. TYPE  QueuePtrType  = ^QueueRecType;
  22.       QueueRecType  = RECORD                     {Queue-Element}
  23.                         Data     : Pointer;      {Zeiger auf Datenbereich}
  24.                         Next     : QueuePtrType; {Zeiger auf nächstes Element}
  25.                       END;
  26.       QueDataType   = LongInt;
  27.       QueueType     = RECORD                     {Anker der Queue}
  28.                         Critical : Pointer;      {Semaphore für Update-Zugriff}
  29.                         Elements : Pointer;      {Element-Count}
  30.                         QueData  : QueDataType;  {User-Defined Data}
  31.                         First    : QueuePtrType; {Zeiger auf Queue-Anfang}
  32.                         Last     : QueuePtrType; {Zeiger auf Queue-Ende}
  33.                       END;
  34.  
  35. PROCEDURE AppendRec(VAR QueueRec:QueueType; Data:Pointer);
  36. FUNCTION  RemoveRec(VAR QueueRec:QueueType; Data:Pointer):Pointer;
  37. PROCEDURE CreQueue(VAR Q:QueueType);
  38. FUNCTION  DeleteQueue(VAR Q:QueueType):BOOLEAN;
  39. FUNCTION  FindRec(VAR QueueRec:QueueType; Vergleichswert, Func:Pointer):Pointer;
  40. PROCEDURE SafeGetMem(VAR x; Size:Word);
  41. PROCEDURE SafeFreeMem(VAR x; Size:Word);
  42.  
  43. {-----------------------------------------------------------------------------}
  44.  
  45. IMPLEMENTATION
  46.  
  47. TYPE QueueErrType  = (QueCreSem, QueRemSem, QueHeap);
  48.  
  49. VAR  ProcAddr    : Pointer;
  50.      SearchQueue : Pointer;
  51.  
  52. {-----------------------------------------------------------------------------}
  53.  
  54. PROCEDURE SafeFreeMem(VAR x; Size:Word);
  55. {
  56.   Freigabe von Speicher unter Blockierung der CPU
  57. }
  58.  
  59. VAR  P : Pointer absolute x;
  60.  
  61. BEGIN {SafeFreeMem}
  62.   BindCPU;
  63.   FreeMem(P,Size);
  64.   ReleaseCPU;
  65. END;  {SafeFreeMem}
  66.  
  67. {-----------------------------------------------------------------------------}
  68.  
  69. PROCEDURE SafeGetMem(VAR x; Size:Word);
  70. {
  71.   Freigabe von Speicher unter Blockierung der CPU
  72. }
  73.  
  74. VAR  P : Pointer absolute x;
  75.  
  76. BEGIN {SafeGetMem}
  77.   BindCPU;
  78.   GetMem(P,Size);
  79.   ReleaseCPU;
  80. END;  {SafeGetMem}
  81.  
  82. {-----------------------------------------------------------------------------}
  83.  
  84. PROCEDURE QueueErr(ErrNo:QueueErrType);
  85.  
  86. BEGIN {QueueErr}
  87.   Write(^G'Queue: ');
  88.   CASE ErrNo OF
  89.     QueHeap:   Writeln('Zuwenig dynamischer Speicher vorhanden!');
  90.     QueCreSem: Writeln('Fehler beim Anlegen einer Semaphore!');
  91.     QueRemSem: Writeln('Fehler beim Löschen einer Semaphore!');
  92.   ELSE Writeln('Unbekannter Fehler: ',Byte(ErrNo));
  93.   END;
  94.   Halt(1);
  95. END;  {QueueErr}
  96.  
  97. {-----------------------------------------------------------------------------}
  98.  
  99. PROCEDURE AppendRec(VAR QueueRec:QueueType; Data:Pointer);
  100.  
  101. { Anhängen eines Elementes an die durch QueueRec verwaltete Queue.
  102.   Für das Element wird ein Verwaltungssatz angelegt. Fehlt der hierfür er-
  103.   forderliche dynamische Speicher, so wird die Aktion abgebochen!
  104.   Zum Abschluß der Aktion wird der Element-Count der Queue erhöht!
  105. }
  106.  
  107. VAR   Elem : QueuePtrType;
  108.  
  109. BEGIN {AppendRec}
  110.   IF MaxAvail < SizeOf(QueueRecType)
  111.      THEN QueueErr(QueHeap);
  112.  
  113.   SafeGetMem(Elem,SizeOf(Elem^));                {erzeuge Verwaltungssatz}
  114.   Elem^.Next := NIL;                             {Bildet das Kettenende}
  115.   Elem^.Data := Data;                            {hänge Datenbereich ein}
  116.  
  117.   WITH QueueRec DO
  118.   BEGIN
  119.     SemWait(Critical);                           {Kritischer Bereich}
  120.     IF First = NIL                               {erstes Kettenelement}
  121.        THEN First := Elem
  122.        ELSE Last^.Next := Elem;                  {Verketten}
  123.     Last := Elem;                                {neues Kettenende merken}
  124.     SemSignal(Critical);                         {Freigeben der Queue}
  125.     SemSignal(Elements);                         {Erhöhe Anzahl Elemente}
  126.   END;
  127. END; {AppendRec}
  128.  
  129. {-----------------------------------------------------------------------------}
  130.  
  131. FUNCTION RemoveRec(VAR QueueRec:QueueType; Data:Pointer):Pointer;
  132.  
  133. {
  134.   Entfernen des Queue-Elementes auf dessen Datenbereich der Zeiger Data
  135.   verweist. Dieser Zeiger MUSS auf ein gültiges Kettenelement verweisen, da
  136.   zur Verbesserung der Performance von dieser Voraussetzung ausgegangen wird.
  137.   Fehlerhafte Datenbereichszeiger werden mit einiger Sicherheit im Nirwana
  138.   enden; günstigsten Falles jedoch mit einer ungültige Pointeroperation.
  139.   Der Verwaltungssatz zu diesem Element wird freigegeben.
  140.   ACHTUNG!!! Der Element-Count wird NICHT verändert, da in der Regel auf die
  141.   Warteschlange über ein SemWait(Elements) zugegriffen wird, wenn die Entnahme
  142.   von Daten beabsichtigt ist. Durch diesen Aufruf wurde der Element-Count be-
  143.   reits vor Aufruf von RemoveRec erniedrigt.
  144. }
  145.  
  146. LABEL ExitRemove;
  147.  
  148. VAR   zElem : QueuePtrType;
  149.       Elem  : QueuePtrType;
  150.  
  151. BEGIN {RemoveRec}
  152.   RemoveRec := Data;                          { Zeiger auf Elem zurückliefern }
  153.  
  154.   WITH QueueRec DO
  155.   BEGIN
  156.     SemWait(Critical);                        { Exclusiver Zugriff erforderlich}
  157.     Elem := First;                            { für 2 Fälle zutreffend }
  158.     IF First = Last                           { nur 1 Kettenelement }
  159.        THEN BEGIN
  160.               First := NIL;
  161.               Last  := NIL;
  162.               Goto ExitRemove;
  163.             END;
  164.  
  165.     IF First^.Data = Data                     { erstes Element! }
  166.        THEN BEGIN
  167.               First := First^.Next;
  168.               Goto ExitRemove;
  169.             END;
  170.  
  171.     Elem  := First;                           { suche den Verwaltungssatz }
  172.     WHILE Elem^.Data <> Data DO
  173.       Elem := Elem^.Next;
  174.  
  175.     zElem := First;                           { suche Vorgänger von "Elem" }
  176.     WHILE zElem^.Next <> Elem DO
  177.       zElem := zElem^.Next;
  178.  
  179.     zElem^.Next := Elem^.Next;                { Element ausketten }
  180.  
  181.     IF Elem = Last                            { ggf. Last-Zeiger aktualisieren }
  182.        THEN Last := zElem;
  183.  
  184. ExitRemove:
  185.     SafeFreeMem(Elem,SizeOf(Elem^));          { Freigeben Verwaltungssatz}
  186.     SemSignal(Critical);                      { Freigeben der Queue }
  187.   END;
  188. END;  {RemoveRec}
  189.  
  190. {-----------------------------------------------------------------------------}
  191.  
  192. PROCEDURE CreQueue(VAR Q:QueueType);
  193.  
  194. { Anlegen und Initialisieren einer Queue }
  195.  
  196. BEGIN {CreQueue}
  197.   WITH Q DO
  198.   BEGIN
  199.     IF (CreateSem(Critical) <> Sem_Ok) OR
  200.        (CreateSem(Elements) <> Sem_Ok)
  201.        THEN QueueErr(QueCreSem);
  202.  
  203.     SemClear(Elements);
  204.     First     := NIL;
  205.     Last      := NIL;
  206.   END;
  207. END;  {CreQueue}
  208.  
  209. {-----------------------------------------------------------------------------}
  210.  
  211. FUNCTION DeleteQueue(VAR Q:QueueType):BOOLEAN;
  212. {
  213.   Löschen einer Queue, sofern diese derzeit keine Elemente enthält.
  214.   Aller durch die Semaphoren belegte Speicherplatz wird wieder freigegeben.
  215.   Ist die Warteschlange einer Semaphore nicht leer, oder enthält die Queue
  216.   noch Elemente, so zeigt der Funktionswert FALSE Mißerfolg an.
  217. }
  218. BEGIN {DeleteQueue}
  219.   DeleteQueue := False;
  220.   WITH Q DO
  221.   BEGIN
  222.     IF (First <> NIL)         OR
  223.        SemSoWaiting(Critical) OR
  224.        SemSoWaiting(Elements)
  225.        THEN Exit;
  226.  
  227.     IF (RemoveSem(Critical) <> Sem_OK) OR
  228.        (RemoveSem(Elements) <> Sem_OK)
  229.        THEN QueueErr(QueRemSem);
  230.   END;
  231.   DeleteQueue := True;
  232. END;  {DeleteQueue}
  233.  
  234. {-----------------------------------------------------------------------------}
  235.  
  236. FUNCTION ElemFound(Vergleichswert, Data:Pointer):BOOLEAN;
  237.   INLINE($FF/$1E/ProcAddr);   { CALL FAR [ProcAddr] }
  238.  
  239. { siehe Turbo 4.0 Beispielprogramm PROCPTR.PAS }
  240.  
  241. {-----------------------------------------------------------------------------}
  242.  
  243. FUNCTION FindRec(VAR QueueRec:QueueType; Vergleichswert, Func:Pointer):Pointer;
  244.  
  245. {
  246.   Durchsuchen einer Queue nach einem bestimmten Element.
  247.   Der Parameter Data ist ein Zeiger auf ein irgendwie geartetes Datenelement,
  248.   das die durch Func angesprochene Funktion als Vergleichswert benötigt.
  249.   Func ist ein Zeiger auf eine Funktion, die als Parameter zwei Zeiger, einen
  250.   auf den Vergleichswert und einen auf den Datenbereich eines Queue-Elements
  251.   erhält. Der Funktionswert dieser Funktion zeigt an, ob das gesuchte Element
  252.   gefunden werden konnte. True = Gefunden. Diese Funktion muß eine FAR-Funk-
  253.   tion sein, also z. B. mit dem Compilerswitch F+ compiliert worden sein.
  254.   Kann in der gesamten Queue kein passendes Element gefunden werden, so lie-
  255.   fert FindRec NIL, anderenfalls einen Zeiger auf den Datenbereich des ge-
  256.   fundenen Kettenelementes.
  257.   Während der Suche wird die Queue blockiert, um gleichzeitige Updates auszu-
  258.   schließen. Ferner wird durch die Semaphore SearchQueue gewährleistet, daß
  259.   zu einem Zeitpunkt immer nur eine Suchanforderung aktiv sein kann. Dies ist
  260.   erforderlich, da jede Suchanforderung die globale Variable ProcAddr verän-
  261.   dert, die auf die Vergleichsfunktion verweist.
  262. }
  263.  
  264. LABEL ExitFindRec;
  265.  
  266. VAR   Elem : QueuePtrType;
  267.  
  268. BEGIN {FindRec}
  269.   SemWait(SearchQueue);                          {ProcAddr exclusiv anfordern}
  270.   ProcAddr := Func;                              {bereite Funktionsaufruf vor}
  271.   FindRec  := NIL;
  272.   WITH QueueRec DO
  273.   BEGIN
  274.     SemWait(Critical);                           {blockiere die Queue}
  275.     IF First = NIL
  276.        THEN Goto ExitFindRec                     {Queue leer}
  277.        ELSE Elem := First;                       {initialisiere Arbeitspointer}
  278.  
  279.     WHILE (Elem <> NIL) DO
  280.       IF ElemFound(Vergleichswert,Elem^.Data)
  281.          THEN BEGIN                              {Eintrag gefunden}
  282.                 FindRec := Elem^.Data;
  283.                 Goto ExitFindRec;
  284.               END
  285.          ELSE Elem := Elem^.Next;                {weiter mit Folgeelement}
  286.  
  287. ExitFindRec:
  288.     SemSignal(Critical);
  289.     SemSignal(SearchQueue);
  290.   END;
  291. END;  {FindRec}
  292.  
  293. {-----------------------------------------------------------------------------}
  294.  
  295. BEGIN {Initialisierung}
  296. IF CreateSem(SearchQueue) <> Sem_OK
  297.    THEN QueueErr(QueCreSem);
  298. END.  {Initialisierung}
  299.  
  300. {//////////////////////////////////////////////////////////////////////////////
  301. ///                    Ende des Moduls                                      ///
  302. //////////////////////////////////////////////////////////////////////////////}
  303.