Document revision date: 19 July 1999
[Compaq] [Go to the documentation home page] [How to order documentation] [Help on this site] [How to contact us]
[OpenVMS documentation]

OpenVMS Programming Concepts Manual


Previous Contents Index

16.6.7 Wait Form Services and SYS$SYNCH

A wait form system service is a variant of an asynchronous service in which there is a service request and then a wait for the completion of the request. The SYS$SYNCH system service checks the completion status of a system service that completes asynchronously. For reliable operation in most applications, the service whose completion status is to be checked must have been called with the efn and iosb arguments specified. The SYS$SYNCH service uses the event flag and I/O status block of the service to be checked.

Compaq recommends that only EFN$C_ENF be used for concurrent use of event flags.

16.6.8 Event Flag Waits

The following three system services place the process or thread in a wait state until an event flag or a group of event flags is set:

Another system service that accepts an event flag number as an argument is the Queue I/O Request (SYS$QIO) system service. The following example shows a program segment that issues two SYS$QIO system service calls and uses the SYS$WFLAND system service to wait until both I/O operations complete before it continues execution:


 
 
   .
   .
   .
        unsigned int status, efn1=1, efn2=2, mask; 
   .
   .
   .
 
/* Issue first I/O request and check for error */ 
        status = SYS$QIO( efn1,...) 
        if ((status & 1) != 1)                                 (1)
                LIB$SIGNAL(status); 
 
/* Issue second I/O request and check for error */  
        status = SYS$QIO( efn2,...) 
        if ((status & 1) != 1) 
                LIB$SIGNAL(status); 
 
/* Wait until both complete and check for error */               (2)
        mask = efn1 || efn2;                      
        status = SYS$WFLAND( efn1, mask );                       (3)
        if ((status & 1) != 1) 
                LIB$SIGNAL(status); 
   .
   .
   .
 

  1. The event flag argument is specified in each SYS$QIO request. Both of these event flags are in cluster 0.
  2. After both I/O requests are queued successfully, the program calls the SYS$WFLAND system service to wait until the I/O operations complete. In this service call, the efn argument can specify any event flag number in the cluster containing the event flags to be waited for. The mask argument specifies to wait for flags 1 and 2.
  3. Note that the SYS$WFLAND system service (and the other wait system services) waits for the event flag to be set; it does not wait for the I/O operation to complete. If some other event were to set the required event flags, the wait for event flag would complete prematurely. Use of event flags must be coordinated carefully.

16.6.9 Setting and Clearing Event Flags

System services that use event flags clear the event flag specified in the system service call before they queue the timer or I/O request. This ensures that the process knows the state of the event flag. If you are using event flags in local clusters for other purposes, be sure the flag's initial value is what you want before you use it.

The Set Event Flag (SYS$SETEF) and Clear Event Flag (SYS$CLREF) system services set and clear specific event flags. For example, the following system service call clears event flag 32:


$CLREF_S EFN=#32 

The SYS$SETEF and SYS$CLREF services return successful status codes that indicate whether the specified flag was set or cleared when the service was called. The caller can thus determine the previous state of the flag, if necessary. The codes returned are SS$_WASSET and SS$_WASCLR.

All event flags in a common event flag cluster are initially clear when the cluster is created. Section 16.6.10 describes the creation of common event flag clusters.

16.6.10 Example of Using a Common Event Flag Cluster

The following example shows four cooperating processes that share a common event flag cluster. The processes named ORION, CYGNUS, LYRA, and PEGASUS are in the same group.


 
 
/* **** Process ORION **** */ 
 
   .
   .
   .
        unsigned int status, efn=64; 
        $DESCRIPTOR(name,"TITUS"); 
   .
   .
   .
/* Create a common cluster */ 
                                                                 (1)
        status = SYS$ASCEFC(efn, &name,...);             (2)
        if ((status & 1) != 1) 
                LIB$SIGNAL(status); 
   .
   .
   .
        mask = efn1 || efn2 || efn3; 
 
/* Wait for flags 1, 2, and 3 */ 
 
        status = SYS$WFLAND(efn, mask);                           (3)
        if ((status & 1) != 1) 
                LIB$SIGNAL(status); 
   .
   .
   .
/* Disassociated cluster */ 
 
        status = SYS$DACEFC(efn);                                 (4)
 
 
/* **** Process CYGNUS **** */ 
 
   .
   .
   .
        unsigned int status, efn1=64,efn2=64; 
        $DESCRIPTOR(name,"TITUS"); 
   .
   .
   .
        status = SYS$ASCEFC(efn1,&name,...);              (5)
        if ((status & 1) != 1) 
                LIB$SIGNAL(status); 
 
/* Set event flag 1 and check for error */ 
        status = SYS$SETEF(efn2); 
        if ((status & 1) != 1) 
                LIB$SIGNAL(status); 
   .
   .
   .
        status = SYS$DACEFC(efn1);                             
 
/* **** Process LYRA **** */ 
        $DESCRIPTOR(name,"TITUS"); 
...
 
/* Associate with cluster 3 */ 
        status = SYS$ASCEFC(efn, &name);                      (6)
        if ((status & 1) != 1) 
                LIB$SIGNAL(status); 
 
/* Set event flag 3 and check for error */ 
        status = SYS$SETEF(efn2); 
        if ((status & 1) != 1) 
                LIB$SIGNAL(status); 
   .
   .
   .
        status = SYS$DACEFC(efn1); 
 
 
/* **** Process PEGASUS **** */ 
 
/* Associate with cluster  */ 
        status = SYS$ASCEFC(efn, &name);                        (7)
        if ((status & 1) != 1) 
                LIB$SIGNAL(status); 
 
/* Wait for flag 1 and check for error */ 
        status = SYS$WAITFR(efn2); 
        if ((status & 1) != 1) 
                LIB$SIGNAL(status); 
 
/* Set event flag 2 and check for error */ 
        status = SYS$SETEF(efn2); 
        if ((status & 1) != 1) 
                LIB$SIGNAL(status); 
   .
   .
   .
        status = SYS$DACEFC(efn1); 
 

  1. Assume that ORION is the first process to issue the SYS$ASCEFC system service and, therefore, is the creator of the cluster. Because this is a newly created cluster, all event flags in it are clear.
  2. The argument name in the SYS$ASCEFC system service call is a pointer to the descriptor CNAME for the name to be assigned to the cluster; in this example, the cluster is named TITUS. This service call associates this name with cluster 2 of process ORION and contains event flags 64 through 95. Cooperating processes CYGNUS, LYRA, and PEGASUS must use the same character string name to refer to this cluster.
  3. The continuation of process ORION depends on work done by processes CYGNUS, LYRA, and PEGASUS. The SYS$WFLAND system service call specifies a mask indicating the event flags that must be set before process ORION can continue. The mask in this example (^B1110) indicates that the second, third, and fourth flags in the cluster must be set.
  4. When all three event flags are set, process ORION continues execution and calls the SYS$DACEFC system service. Because ORION did not specify the perm argument when it created the cluster, TITUS is deleted.
  5. Process CYGNUS executes, associates with the cluster, sets event flag 65 (flag 1 in the cluster), and disassociates.
  6. Process LYRA associates with the cluster, but instead of referring to it as cluster 2, it refers to it as cluster 3 (with event flags in the range 96 through 127). Thus, when process LYRA sets flag 99, it sets flag 3 in TITUS.
  7. Process PEGASUS associates with the cluster, waits for an event flag set by process CYGNUS, and sets an event flag itself.

16.6.11 Example of Using Event Flag Routines and Services

This section contains an example of how to use event flag services.


Common event flags are often used for communicating between a parent process and a created subprocess. In the following example, REPORT.FOR creates a subprocess to execute REPORTSUB.FOR, which performs a number of operations.

After REPORTSUB.FOR performs its first operation, the two processes can perform in parallel. REPORT.FOR and REPORTSUB.FOR use the common event flag cluster named JESSIER to communicate.

REPORT.FOR associates the cluster name with a common event flag cluster, creates a subprocess to execute REPORTSUB.FOR and then waits for REPORTSUB.FOR to set the first event flag in the cluster. REPORTSUB.FOR performs its first operation, associates the cluster name JESSIER with a common event flag cluster, and sets the first flag. From then on, the processes execute concurrently.

#1

 
                         REPORT.FOR 
. 
. 
. 
! Associate common event flag cluster 
STATUS = SYS$ASCEFC (%VAL(64), 
2                    'JESSIER',,) 
IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS)) 
 
! Create subprocess to execute concurrently 
MASK = IBSET (MASK,0) 
STATUS = LIB$SPAWN ('RUN REPORTSUB', ! Image 
2                   'INPUT.DAT',     ! SYS$INPUT 
2                   'OUTPUT.DAT',    ! SYS$OUTPUT 
2                   MASK 
IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS)) 
 
! Wait for response from subprocess. 
STATUS = SYS$WAITFR (%VAL(64)) 
IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS)) 
. 
. 
. 
 
REPORTSUB.FOR 
. 
. 
. 
! Do operations necessary for 
! continuation of parent process. 
. 
. 
. 
! Associate common event flag cluster 
STATUS = SYS$ASCEFC (%VAL(64), 
2                    'JESSIER',,) 
IF (.NOT. STATUS) 
2  CALL LIB$SIGNAL (%VAL(STATUS)) 
 
! Set flag for parent process to resume 
STATUS = SYS$SETEF (%VAL(64)) 
. 
. 
. 
      

16.7 Synchronizing Operations with Parallel Processing Run-Time Routines

The Parallel Processing facility (PPL$) consists of routines for synchronizing program processing in a synchronous multiprocessing configuration. The routines provide for the following capabilities:

To use the PPL$ routines, you must call the PPL$ initialization routine (PPL$INITIALIZE) that sets up data structures and memory areas required for parallel processing run-time routines. Then, when use of the PPL$ routines is no longer required, you must free those data structures and memory areas with PPL$TERMINATE before exiting from the program.

Refer to the OpenVMS RTL Parallel Processing (PPL$) Manual for more information.

16.7.1 Using Subprocesses

Once you have initialized the parallel processing environment, you can create one or more subprocesses to execute images. You may execute the same or different images within each subprocess. Even though you can create a subprocess with PPL$SPAWN that will run outside of a parallel processing environment, you should limit its use to subprocesses within a parallel processing environment.

To delete one or more subprocesses created with PPL$SPAWN, use PPL$STOP.

16.7.2 Using Spin Locks

To ensure that only one process at a time can access a critical region or physical resource of a parallel task, you can use spin locks. A spin lock is a lock on a critical region where the lock constantly tests to determine whether access to that region is available. Because of the constant testing, this technique is CPU intensive. An alternative technique to ensure single access is to use semaphores. Refer to Section 16.7.3 for more information on using semaphores.

The three spinlock routines are as follows:

16.7.3 Using Semaphores

Semaphores also synchronize access to a critical region or physical device by controlling the number of processes that have access. Unlike spin locks, using semaphores is not CPU intensive.

There are two type of semaphores: binary and counting. A binary semaphore has a value of 0 or 1 and allows only one process to access a resource. A process can access the resource when the semaphore value is 1. A process waits for the resource when the semaphore value is 0. A counting semaphore can have any positive value, thereby allowing you to control access to multiple resources.

The semaphore routines are as follows:

16.7.4 Using Barrier Synchronization

Barrier synchronization specifies a point in a program that all parallel paths must reach before any are allowed to continue. Only one barrier can be set up within a program.

The barrier routines are as follows:

Once you specify a barrier point, all program paths must call PPL$WAIT_AT_BARRIER in order to be included in the barrier synchronization.

16.8 Synchronizing Operations with System Services

A number of system services can be executed either synchronously or asynchronously such as the following:

The W at the end of the system service name indicates the synchronous version of the service.

The asynchronous version of a system service queues a request and immediately returns control to your program pending the completion of the request. You can perform other operations while the system service executes. To avoid data corruptions, you should not attempt any read or write access to any of the buffers or itemlists referenced by the system service call prior to the completion of the asynchronous portion of the system service call. Further, no self-referential or self-modifying itemlists should be used.

Typically, you pass an event flag and an I/O status block to an asynchronous system service. When the system service completes, it sets the event flag and places the final status of the request in the I/O status block. Use the SYS$SYNCH system service to ensure that the system service has completed. You pass to SYS$SYNCH the event flag and I/O status block that you passed to the asynchronous system service; SYS$SYNCH waits for the event flag to be set and then examines the I/O status block to be sure that the system service rather than some other program set the event flag. If the I/O status block is still 0, SYS$SYNCH waits until the I/O status block is filled.

The following example show the use of the SYS$GETJPI system service:


! Data structure for SYS$GETJPI 
   .
   .
   .
INTEGER*4 STATUS, 
2         FLAG, 
2         PID_VALUE 
! I/O status block 
STRUCTURE /STATUS_BLOCK/ 
 INTEGER*2 JPISTATUS, 
2          LEN 
 INTEGER*4 ZERO /0/ 
END STRUCTURE 
RECORD /STATUS_BLOCK/ IOSTATUS 
   .
   .
   .
! Call SYS$GETJPI and wait for information 
STATUS = LIB$GET_EF (FLAG) 
IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS)) 
STATUS = SYS$GETJPI (%VAL(FLAG), 
2                    PID_VALUE, 
2                    , 
2                    NAME_BUF_LEN, 
2                    IOSTATUS, 
2                    ,) 
IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS)) 
   .
   .
   .
STATUS = SYS$SYNCH (%VAL(FLAG), 
2                   IOSTATUS) 
IF (.NOT. IOSTATUS.JPISTATUS) THEN 
  CALL LIB$SIGNAL (%VAL(IOSTATUS.JPISTATUS)) 
END IF 
 
END 

The synchronous version of a system service acts as if you had used the asynchronous version followed immediately by a call to SYS$SYNCH; however, it behaves this way only if you specify a status block. If you omit the I/O status block, the result is as though you called the asynchronous version followed by a call to SYS$WAITFR. Regardless of whether you use the synchronous or asynchronous version of a system service, if you omit the efn argument, the service uses event flag 0.


Previous Next Contents Index

  [Go to the documentation home page] [How to order documentation] [Help on this site] [How to contact us]  
  privacy and legal statement  
5841PRO_049.HTML