home *** CD-ROM | disk | FTP | other *** search
/ C!T ROM 2 / ctrom_ii_b.zip / ctrom_ii_b / PROGRAM / PASCAL / MULTI12 / MULTI.DOC < prev    next >
Text File  |  1989-06-04  |  27KB  |  669 lines

  1.    1. Introduction
  2.    ---------------
  3.  
  4.    The following is a description of the MULTI unit for Turbo Pascal 4.0 or
  5. later. The unit will allow you to run several TP-procedures as concurrent
  6. processes. It also provides facilities for synchronizing the processes and for
  7. communication between them.
  8.    The parallellism implied is not strictly true: your computer (presumably)
  9. has only one processor and what the unit does is to share that processors time
  10. between the various processes to create an illusion of parallel processing.
  11. This assembly of concurrently executing procedures is called a multiprogram.
  12.    The unit will run on any IBM PC or compatible computer with Turbo Pascal
  13. version 4.0 or 5.0. You may need to change some interrupt numbers, see
  14. section 8.
  15.    This file should be a part of a package containing the following files:
  16.  
  17.              MULTI.PAS     - Source file for the unit
  18.              MULTI.TPU     - TP5 compiled version of the unit
  19.              MULTI.DOC     - This file - documentation of the unit
  20.              MUL_DEMO.PAS  - Demo program - source file
  21.              MUL_DEMO.EXE  - Executable version of demo program
  22.              JABWOCK.DAT   - Data file used by demo program
  23.  
  24.  
  25.    2. Managing Processes
  26.    ---------------------
  27.  
  28.    The unit will allow you to specify that several of your programs procedures
  29. are to be executed in parallel. You can also execute several copies of the
  30. same procedure. The unit contains the follwing procedures for managing
  31. processes:
  32.  
  33. Procedure CreateProcess           Adds a new process to the multiprogram.
  34. Procedure Kill                    Kills the specified process, i.e. removes
  35.                                   it from the multiprogram.
  36. Procedure Die                     Causes a process to commit suicide, i.e.
  37.                                   it removes itself from the multiprogram.
  38. Function  NoProcesses             Returns the number of processes currently in
  39.                                   the multiprogram.
  40.  
  41.  
  42.    3. Managing the multiprogram
  43.    ----------------------------
  44.  
  45.    There are two operations you can perform on the multiprogram as a whole:
  46. you can start it, and you can stop it. When you start your program it will
  47. execute as a normal, sequential program. You then define some processes using
  48. CreateProcess. The processes start executing when you start the multiprogram,
  49. and stops when you stop the multiprogram. The relevant procedures are:
  50.  
  51. Procedure StartMulti              Starts the multiprogram, commencing
  52.                                   execution of the processes.
  53. Procedure StopMulti               Stops the multiprogram, returns control
  54.                                   to the normal, sequential program.
  55.  
  56.  
  57.    4. Synchronizing processes
  58.    --------------------------
  59.  
  60.    Normally, you want to be able to coordinate what you processes do to
  61. avoid conflict between them. This is done by means of semaphores. They
  62. are used for allocating nonshareble resources such as the disk or the
  63. keyboard. The semaphores in the multi unit are integer semaphores consisting
  64. of a counter and a queue. The two basic operations on these semaphores are
  65. wait and signal defined as follows:
  66.  
  67. wait :   Begin
  68.            While counter<=0 Do sleep;
  69.            counter:=counter-1;
  70.          End;
  71.  
  72. signal : Begin
  73.            counter:=counter+1;
  74.            If any processes are waiting Then wake one up;
  75.          End;
  76.  
  77.   Also, you must initialize the semaphore before using it giving a total of
  78. three semaphore operations:
  79.  
  80. Procedure Wait                    Performs wait-operation on semaphore.
  81. Procedure Signal                  Performs signal-operation on semaphore.
  82. Procedure InitSem                 Initializes semaphore.
  83.  
  84.  
  85.  
  86.    5. Communication between processes
  87.    ----------------------------------
  88.  
  89.    There are two methods for communicating between processes: shared data and
  90. message passing. The data structures declared in the main program reside in
  91. the data segment and are common to all processes. However, there is no
  92. proctection against simultanious acces by several processes, so you will
  93. have to guard your shared data with sempahores to prevent this.
  94.   The other method, message passing, is implemented using message semaphores.
  95. A message semaphore is a billboard where a process can pin messages. Another
  96. process can then read the message and take appropriate action according to
  97. the content of the message. A message is a data structure which can have any
  98. form. The only constraint is that the unit uses the first 8 bytes (two
  99. pointers) for internal administration. A message could for example be declared
  100. like this:
  101.  
  102.        message = Record
  103.                    dummy1,              { MUST start with 8 bytes of reserved }
  104.                    dummy2   : Pointer;  { space. }
  105.                    YourData : string;   { You can have any number of fields
  106.                  End;                   { here of any type you like }
  107.  
  108.   There are three operations you can perform on a message semaphore:
  109.  
  110. Procedure PutMsg                  Sends a message to the specified message
  111.                                   semaphore.
  112. Procedure GetMsg                  Reads a message from the specified message
  113.                                   semaphore.
  114. Procedure InitMsgSem              Initializes the specified message semaphore.
  115.  
  116.  
  117.    6. Restrictions
  118.    ---------------
  119.  
  120.    When using the multi unit you must beware of the following restrictions.
  121.  
  122.    a) The unit will not support numeric coprocessors. The multiprogram will
  123.       run on machines with coprocessors but only one process may use it or
  124.       you will get unpredictable results.
  125.  
  126.    b) MSDOS is not reentrant. This meens that only one process at a time can
  127.       use dos functions such as reading from the keyboard, writing to disk
  128.       etc. This shortcomming can be remedied by guarding dos calls by a
  129.       semaphore. You may try to experiment with having, say, a process writing
  130.       to disk while another reads characters from the keyboard but this is
  131.       skating on thin ice. You may examine the accompanying demonstration
  132.       program for an example of how to use dos functions.
  133.  
  134.    c) Some Turbo Pascal routines are not reentrant. This is true of the heap
  135.       manager and the screen output routines. Thus, only one process at a
  136.       time should allocate or release space the heap and write to the screen.
  137.  
  138.    d) The Delay procedure will not work properly when running a multiprogram.
  139.       For some reason, using this procedure will crash the system.
  140.  
  141.    e) It is an error for a process to terminate 'normally', i.e. to reach
  142.       the final End-statement in the procedure body. Should this happen,
  143.       the system will hang. To prevent this you should always place a call
  144.       to procedure Die immediately before the final End-statement in all
  145.       processes.
  146.  
  147.  
  148.    7. Programming considerations
  149.    -----------------------------
  150.  
  151.    Multiprograms are notoriously hard to debug so you will have to be extra
  152. carefull in designing your program. First of all you must ask yourself if you
  153. really need to write your application as a multiprogram. A multiprogram is
  154. not as efficient as a sequential program because some processing power is lost
  155. to administration of the processes, semaphores etc. Multiprograms are well
  156. suited to handling input form various sources at the same time, so
  157. communications programs are good candidates for multiprograms, as are other
  158. programs which interact heavily with the user. Other possible applications are
  159. database programs (you can do sorts, print lists, execute searches in the
  160. database etc as seperate background processes) and word processors (you can
  161. print or reformat text in the background).
  162.   If possible, debug your processes one at a time as sequential programs. When
  163. the multiprogram chrashes, it really CRASHES, often to the point where you
  164. have to switch off your machine to make it work properly. So, lets be carefull
  165. out there.
  166.   There are two factors which will probably limit you in your multiprogram
  167. design. One is the amount of ememy available, the other is the fixed amount
  168. of processor capacity in your system.
  169.   When considering the memory limit you should remember that the processes get
  170. their stack space from the heap. You should therefore try to determine the
  171. memory needs of each process when you create it. Remember that the stack space
  172. is used to hold local variables and call references for procedure calls from
  173. the process. You should be prudent but not mean when allocating stack space
  174. for the processes. You may, however, cut down the stack space for the main
  175. sequential program. This space is only used for call references in the main
  176. program and for a typical multiprogram this will just consist of setting up
  177. the processes and initializing semaphores and other data structures. You can
  178. adjust the amount of stack space allocated to the main program by using the
  179. $M compiler directive.
  180.   If you have a 80286 or 80386 based computer, you should not have any
  181. problems with the capacity of your processor. On a plain vanilla PC you risk
  182. run into trouble with response time even with a relatively modest number of
  183. processes. You can estimate the size of this problem by running the
  184. demonstration program which runs 8 processes in parallel.
  185.  
  186.  
  187.    8. Defined types and constants
  188.    ------------------------------
  189.  
  190.    The interface section of the unit contains the following declarations:
  191.  
  192.  
  193. unit multi;
  194.  
  195. interface
  196.  
  197. uses  Dos;
  198.  
  199.  
  200. const TimerIntNo =  8;                 (* Interruptno. for timer *)
  201.       SavedInt   = 78;                 (* Int.no. for rerouting timer *)
  202.       Interleave =  1;                 (* Interleave factor for timeslicing *)
  203.  
  204. type  ProcedureType     = procedure;
  205.  
  206.       queuetype         = ^ProcDescriptor;
  207.       process           = queuetype;
  208.  
  209.       ProcDescriptor    = Record
  210.                                Next      : queuetype;
  211.                             Inqueue   : ^queuetype;
  212.                      Sseg,
  213.                             SP,
  214.                             ProcStack : Word;
  215.                             ptr       : Pointer;
  216.                           End;
  217.  
  218.  
  219.       semaphore         = Record
  220.                             queue   : queuetype;
  221.                             counter : Integer;
  222.                           End;
  223.  
  224.       Msgtype           = pointer;
  225.  
  226.       MsgSemaphore      = Record
  227.                             ProcQueue,
  228.                             MsgQueue  : queuetype;
  229.                           End;
  230.  
  231.       GetMode           = (stay, return);
  232.  
  233.       SwitchMode        = (Timer, NoTimer);
  234.  
  235.  
  236.  
  237. The constant TimerIntNo specifies the interrupt number of DOS' time function
  238. which triggers 20 times pr. second. If this is different on your machine, you
  239. must change this constant appropriately.
  240. The constant SavedInt specifies an interrupt used by the multi unit. If you
  241. find that the unit does not work with your favorite resident program (SideKick
  242. and the like), you may solve the problem by changing this number.
  243. The constant Interleave specifies the longest timeslice a process can have in
  244. multiples of 50 ms. If you have a multiprogram with relatively little
  245. communication between processes you may improve its performance by increasing
  246. the value of this constant.
  247.  
  248.  
  249.  
  250.    9. Multi reference
  251.    ------------------
  252.  
  253.    This section provides a reference guide to the procedures and functions
  254. of the multi unit in alfabetical order.
  255.  
  256.  
  257. ------------------------------------------------------------------------------
  258.  CreateProcess Procedure                                   Process management
  259. ------------------------------------------------------------------------------
  260.  
  261. Function      Adds a new process to the multiprogram.
  262.  
  263. Declaration   Procedure CreateProcess(body: Pointer; StackSize: word;
  264.                                       var proc: process);
  265.  
  266.  
  267. Remarks       The parameter body should contain the address of the procedure
  268.               to be added as a process to the multiprogram, for example
  269.               @MyProcess. The parameter StackSize determines the amount of
  270.               memory reserved for local variable and further procedure calls
  271.               in the process. The memory is taken from the heap and you may
  272.               allocate 64..65521 bytes. If you allocate less then 1024 bytes
  273.               you should compile your program with the {$S-} directive.
  274.               Otherwise Turbo Pascal will generate a stack overflow error.
  275.               The procedure will return  pointer to a process descriptor
  276.               in the parameter proc. This desciptor is used when referring to
  277.               the process in the kill procedure.
  278.  
  279.  
  280. Example       Program count;
  281.  
  282.               var proc1,proc2 : Process;
  283.  
  284.  
  285.               Procedure MyProcess;
  286.  
  287.               var i : Integer;
  288.  
  289.               Begin
  290.                 For i:=1 to Maxint Do
  291.                   Writeln(i);
  292.  
  293.                 Die;
  294.               End;
  295.  
  296.               Begin { main }
  297.                 CreateProcess(@MyProcess,2000,proc1);
  298.                 CreateProcess(@MyProcess,2000,proc2);
  299.  
  300.                 StartMulti;
  301.               End.
  302.  
  303. Restrictions  You may add processes as long as there is sufficient space
  304.               on the heap. A runtime error is generated if this is not the
  305.               case.
  306.  
  307. See also      Kill, Die, NoProcesses
  308.  
  309.  
  310. ------------------------------------------------------------------------------
  311.  Die Procedure                                             Process Management
  312. ------------------------------------------------------------------------------
  313.  
  314. Function      Causes a process to stop itself.
  315.  
  316. Declaration   Procedure Die;
  317.  
  318. Remarks       The stackspace reserved for the process is released and
  319.               control is transferred to one of the remaining processes. If
  320.               no processes remain, the multiprogram is stopped and execution
  321.               resumes in the main program at the statement following the
  322.               call of StartMulti.
  323.               It is an error for processes to terminate 'normally', i.e. to
  324.               reach the end-statement in the procedure body. Therefore, all
  325.               processes should contain a call to Die immediately before the
  326.               final end-statement.
  327.  
  328. Example       Procedure MyProcess;
  329.  
  330.               Begin
  331.                 Writeln('Do something to show life....');
  332.                 Die;
  333.               End;
  334.  
  335.  
  336. Restrictions  None.
  337.  
  338. See also      Kill, CreateProcess, NoProcesses
  339.  
  340.  
  341. ------------------------------------------------------------------------------
  342.  GetMsg Procedure                                               Communication
  343. ------------------------------------------------------------------------------
  344.  
  345. Function      Reads a message from the message semaphore MsgSem.
  346.  
  347. Declaration   Procedure GetMsg(var MsgSem: MsgSemaphore; var Msg : Pointer;
  348.                                mode: Getmode);
  349.  
  350.  
  351. Remarks       A pointer to the message is returned in Msg. You can choose
  352.               between two modes of getting: if the parameter mode=stay, the
  353.               process will wait until a message arrives at the message
  354.               semaphore. If mode=return, if will return immediately and if
  355.               there was no message Msg will be nil.
  356.  
  357.  
  358. Example       type MyMessageType = record
  359.                                      dummy1,
  360.                                      dummy2 : Pointer;
  361.                                      news   : string;
  362.                                    End;
  363.  
  364.  
  365.               Procedure Reader;
  366.  
  367.               var ptr     : pointer;
  368.                   message : ^MyMessageType;
  369.  
  370.               Begin
  371.                 Repeat
  372.                   GetMsg(billboard,ptr,stay);
  373.                   message:=ptr;
  374.                   Writeln('News: ',message^.news);
  375.                 Until
  376.                   false;
  377.               End;
  378.  
  379. Restrictions  The message semaphore must be intialized before use.
  380.  
  381. See also      PutMsg, InitMsgSem
  382.  
  383.  
  384. ------------------------------------------------------------------------------
  385.  InitMsgSem Procedure                                           Communication
  386. ------------------------------------------------------------------------------
  387.  
  388. Function      Initializes the message semaphore.
  389.  
  390. Declaration   Procedure InitMsgSem(var MsgSem : MsgSemaphore);
  391.  
  392.  
  393. Remarks       MUST be called before the message semaphore is used.
  394.  
  395. Restrictions  May NOT be called when the semaphore is in use.
  396.  
  397. See also      PutMsg, GetMsg
  398.  
  399.  
  400. ------------------------------------------------------------------------------
  401.  InitSem Procedure                                            Synchronization
  402. ------------------------------------------------------------------------------
  403.  
  404. Function      Initializes the semaphore setting the counter to 0.
  405.  
  406. Declaration   Procedure InitSem(var sem : semaphore);
  407.  
  408.  
  409. Remarks       MUST be called before semaphore is used. If you want the counter
  410.               of the semaphore set to some value other than 0 you can do this
  411.               by repeated calls to Signal which will increment counter. If you
  412.               need to set counter to some monstrously large value you can set
  413.               it directly by sem.counter:=whatever. However this is not
  414.               recommended.
  415.  
  416. Restrictions  may NOT be called when the semaphore is in use.
  417.  
  418. See also      Signal, Wait
  419.  
  420.  
  421. ------------------------------------------------------------------------------
  422.  Kill Procedure                                            Process Management
  423. ------------------------------------------------------------------------------
  424.  
  425. Function      Stops the specified process and removes it from the multi-
  426.               program.
  427.  
  428. Declaration   Procedure Kill(proc: process);
  429.  
  430.  
  431. Remarks       The stackspace reserved for the killed process is released.
  432.  
  433. Example       Procedure spawn;
  434.  
  435.               var child : process;
  436.  
  437.               Begin
  438.                 { Make clone of process }
  439.                 CreateProcess(@spawn,2000,child);
  440.  
  441.                 { Wait a little while }
  442.                 Delay(500);
  443.  
  444.                 { Then kill it again }
  445.                 Kill(child);
  446.               End;
  447.  
  448. Restrictions  Kill will kill anything and anybody. No process is safe from
  449.               being killed by another. So use with care.
  450.  
  451. See also      CreateProcess, Die, NoProcesses
  452.  
  453.  
  454. ------------------------------------------------------------------------------
  455.  NoProcesses Function                                      Process Management
  456. ------------------------------------------------------------------------------
  457.  
  458. Function      Returns the number of processes currently in the system.
  459.  
  460. Declaration   Function  NoProcesses : Integer;
  461.  
  462.  
  463. Example       Procedure monitor;
  464.  
  465.               Begin
  466.                 Repeat
  467.                   Writeln(NoProcesses);
  468.                 Until
  469.                   false;
  470.               End;
  471.  
  472. Restrictions  None.
  473.  
  474. See also      CreateProcess, Die, Kill
  475.  
  476.  
  477. ------------------------------------------------------------------------------
  478.  PutMsg Procedure                                               Communication
  479. ------------------------------------------------------------------------------
  480.  
  481. Function      Sends a message to a message semaphore.
  482.  
  483. Declaration   Procedure PutMsg(var MsgSem : MsgSemaphore; Msg : Pointer);
  484.  
  485.  
  486. Remarks       The message is sent to the message semaphore MsgSem. The parameter
  487.               Msg should containa pointer to the message begin sent.
  488.  
  489. Example       type MyMessageType = record
  490.                                      dummy1,
  491.                                      dummy2 : Pointer;
  492.                                      news   : string;
  493.                                    End;
  494.  
  495.  
  496.               Procedure talk;
  497.  
  498.               var message : ^MyMessageType;
  499.  
  500.               Begin
  501.                 new(message);
  502.                 message^.news:='Yack Yack Yack');
  503.                 PutMsg(MsgSem,pointer(message));
  504.  
  505.                 Die;
  506.               End;
  507.  
  508. Restrictions  The message semaphore must be initialized.
  509.  
  510. See also      GetMsg, InitMsgSem
  511.  
  512.  
  513. ------------------------------------------------------------------------------
  514.  Signal Procedure                                             Synchronization
  515. ------------------------------------------------------------------------------
  516.  
  517. Function      Performs the signal operation on the semaphore.
  518.  
  519. Declaration   Procedure Signal(var sem: semaphore);
  520.  
  521.  
  522. Remarks       The semaphores counter is incemented. If any processes are
  523.               waiting for this to happen, one of them is awakened.
  524.  
  525. Restrictions  Semaphore must be initialized.
  526.  
  527. See also      InitSem, Wait
  528.  
  529.  
  530. ------------------------------------------------------------------------------
  531.  StartMulti Procedure                                 MultiProgram Management
  532. ------------------------------------------------------------------------------
  533.  
  534. Function      Starts execution of the defined processes in the multiprogram.
  535.  
  536. Declaration   Procedure StartMulti(mode : SwitchMode);
  537.  
  538.  
  539. Remarks       The paramater mode indicates whether processes should be timed
  540.               out using the 50 ms timer interrupt. If mode=Timer, timeout is
  541.               enabled, if mode=NoTimer it is disabled. When debugging a
  542.               multiprogram it is preferable to use NoTimer as this will allow
  543.               you to use Turbo Pascal's debugger. When mode=timer a program
  544.               crash usually means that you have yo reset your system.
  545.               However, when mode=notimer, the multiprogram depends on the
  546.               processes voluntarily giving up control of the system. This
  547.               happens when a process calls Signal or PutMsg. If a process
  548.               contains a read-statement or an infinite loop the entire system
  549.               will hang.
  550.  
  551. Restrictions  It is an error to call StartMulti before any processes have
  552.               been declared. Doing so will hang the system.
  553.  
  554. See also      StopMulti
  555.  
  556.  
  557.  
  558. ------------------------------------------------------------------------------
  559.  StopMulti Procedure                                  MultiProgram Management
  560. ------------------------------------------------------------------------------
  561.  
  562. Function      Stops the multiprogram.
  563.  
  564. Declaration   Procedure StopMulti;
  565.  
  566.  
  567. Remarks       When one of the processes calls this procedure or when all
  568.               processes are dead, execution of the multiprogram stops and
  569.               control is returned to the main program. Execution of the
  570.               main program resumes at the statement immediately following
  571.               the call to StartMulti.
  572.  
  573. Restrictions  None.
  574.  
  575. See also      StartMulti
  576.  
  577.  
  578. ------------------------------------------------------------------------------
  579.  Wait Procedure                                               Synchronization
  580. ------------------------------------------------------------------------------
  581.  
  582. Function      Performs the wait operation on a semaphore.
  583.  
  584. Declaration   Procedure Wait(var sem: semaphore);
  585.  
  586.  
  587. Remarks       Decrements the counter of the semaphore. If the counter was 0
  588.               when the procedure was called the process will sleep until a
  589.               call to signal by another process awakes it.
  590.  
  591. Example       var ScreenSem : semaphore;
  592.                   proc1,
  593.                   proc2     : Process;
  594.  
  595.               Procedure print;
  596.  
  597.               Begin
  598.                 For i:=1 to 30000 Do
  599.                 Begin
  600.                   wait(ScreenSem);   { Ensure undisturbed acces to screen }
  601.                   Writeln(i);
  602.                   signal(ScreenSem);
  603.                 End;
  604.  
  605.                 Die;
  606.               End;
  607.  
  608.               Begin { Main }
  609.                 CreateProcess(@print,2000,proc1);
  610.                 CreateProcess(@Print,2000,proc2);
  611.  
  612.                 InitSem(ScreenSem);
  613.                 Signal(ScreenSem);
  614.  
  615.                 StartMulti;
  616.               End.
  617.  
  618. Restrictions  Semaphore must be initialized.
  619.  
  620. See also      InitSem, Signal
  621.  
  622.  
  623.  
  624.    10. Inside the unit
  625.    -------------------
  626.  
  627.    The unit administrates the processes by placing them in various queues.
  628. The status of the process is determined by the queue it is placed in.
  629. There is a queue containing the process currently running (CurrentProc), a
  630. queue for processes that are ready to run but await their turn (Readyqueue),
  631. a queue for processes that have been killed and are waiting to be removed
  632. form the system (Dead). All semaphores and message semaphores contain queues
  633. for the processes that may have to wait for them.
  634.    The queues are implemented as single-linked circular lists. All list
  635. opearations are done by the procedures Enqueue and Dequeue, so if you want
  636. to change the list implementation, all you have to do is to change these two
  637. procedures.
  638.    The unit shares the processor time equally between the processes in the
  639. readyqueue in a round-robin fashion. There are no priorities in the system,
  640. but you can implement that yourself if you like.
  641.    What really is contained in the queues are the proces descriptors which
  642. contain information about the state of each process. Specifically they
  643. store the stack segment and stack pointer of each process, along with a
  644. pointer to the head of the queue in which the process is contained. Switching
  645. process then simply means switching the value of the stack pointer SSeg:Sp.
  646. This is done in the procedure SwitchContext and requires a bit of inline
  647. assembler code.
  648.  
  649.  
  650.    11. Version history
  651.    -------------------
  652.  
  653.    This is version 1.2 of the MULTI unit. The history of the unit is as
  654. follows:
  655.  
  656. V 1.0 : Was the first version released.
  657.  
  658. V 1.1 : Was the second version released. It contained no changes in the
  659.         definitions of the various procedures and funtcions, but corrected
  660.         a few spelling errors in the documentation and the demonstration
  661.         program.
  662.  
  663. V 1.2 : Is this version, the third to be released. In this version a serious
  664.         error was corrected: the previous versions did not run under TP4. This
  665.         has now been corrected. The error was caused by a change in the way
  666.         TP lays out its variables from TP4 to TP5, which made procedure
  667.         SwitchContext crash (may Anders Hejlsberg's beard get stuck in a
  668.         faulty disk-drive).
  669.         Also, Yet Another Batch Of Typing Errors was corrected.