Updated: 11 December 1998 |
OpenVMS Programming Concepts Manual
Previous | Contents | Index |
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); . . . |
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); |
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)) . . . |
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:
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:
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 |
Copyright © Compaq Computer Corporation 1998. All rights reserved. Legal |
5841PRO_049.HTML
|