[ Team LiB ] |
15.3 POSIX:XSI Shared MemoryShared memory allows processes to read and write from the same memory segment. The sys/shm.h header file defines the data structures for shared memory, including shmid_ds, which has the following members.
The shmatt_t data type is an unsigned integer data type used to hold the number of times the memory segment is attached. This type must be at least as large as an unsigned short. 15.3.1 Accessing a shared memory segmentThe shmget function returns an identifier for the shared memory segment associated with the key parameter. It creates the segment if either the key is IPC_PRIVATE or shmflg & IPC_CREAT is nonzero and no shared memory segment or identifier is already associated with key. Shared memory segments are initialized to zero.
If successful, shmget returns a nonnegative integer corresponding to the shared memory segment identifier. If unsuccessful, shmget returns �1 and sets errno. The following table lists the mandatory errors for shmget.
15.3.2 Attaching and detaching a shared memory segmentThe shmat function attaches the shared memory segment specified by shmid to the address space of the calling process and increments the value of shm_nattch for shmid. The shmat function returns a void * pointer, so a program can use the return value like an ordinary memory pointer obtained from malloc. Use a shmaddr value of NULL. On some systems it may be necessary to set shmflg so that the memory segment is properly aligned.
If successful, shmat returns the starting address of the segment. If unsuccessful, shmat returns �1 and sets errno. The following table lists the mandatory errors for shmat.
When finished with a shared memory segment, a program calls shmdt to detach the shared memory segment and to decrement shm_nattch. The shmaddr parameter is the starting address of the shared memory segment.
If successful, shmdt returns 0. If unsuccessful, shmdt returns �1 and sets errno. The shmdt function sets errno to EINVAL when shmaddr does not correspond to the starting address of a shared memory segment. The last process to detach the segment should deallocate the shared memory segment by calling shmctl. 15.3.3 Controlling shared memoryThe shmctl function provides a variety of control operations on the shared memory segment shmid as specified by the cmd parameter. The interpretation of the buf parameter depends on the value of cmd, as described below.
If successful, shmctl returns 0. If unsuccessful, shmctl returns �1 and sets errno. The following table lists the mandatory errors for shmctl.
Table 15.3 gives the POSIX:XSI values of cmd for shmctl.
Example 15.11 detachandremove.cThe detachandremove function detaches the shared memory segment shmaddr and then removes the shared memory segment specified by semid.
15.3.4 Shared memory examplesProgram 4.11 on page 108 monitors two file descriptors by using a parent and a child. Each process echoes the contents of the files to standard output and then writes to standard error the total number of bytes received. There is no simple way for this program to report the total number of bytes received by the two processes without using a communication mechanism such as a pipe. Program 15.5 modifies Program 4.11 so that the parent and child share a small memory segment. The child stores its byte count in the shared memory. The parent waits for the child to finish and then outputs the number of bytes received by each process along with the sum of these values. The parent creates the shared memory segment by using the key IPC_PRIVATE, which allows the memory to be shared among its children. The synchronization of the shared memory is provided by the wait function. The parent does not access the shared memory until it has detected the termination of the child. Program 15.5 calls detachandremove of Example 15.11 when it must both detach and remove the shared memory segment. Program 15.5 monitorshared.cA program to monitor two file descriptors and keep information in shared memory. The parent waits for the child, to ensure mutual exclusion.
Using shared memory between processes that do not have a common ancestor requires the processes to agree on a key, either directly or with ftok and a pathname. Program 13.5 on page 456 used mutex locks to keep a sum and count for threads of a given process. This was particularly simple because the threads automatically share the mutex and the mutex could be initialized statically. Implementing synchronized shared memory for independent processes is more difficult because you must set up the sharing of the synchronization mechanism as well as the memory for the sum and the count. Program 15.6 uses a semaphore and a small shared memory segment to keep a sum and count. Each process must first call the initshared function with an agreed-on key. This function first tries to create a shared memory segment with the given key. If successful, initshared initializes the sum and count. Otherwise, initshared just accesses the shared memory segment. In either case, initshared calls initsemset with the ready flag in shared memory to access a semaphore set containing a single semaphore initialized to 1. This semaphore element protects the shared memory segment. The add and getcountandsum functions behave as in Program 13.5, this time using the semaphore, rather than a mutex, for protection. Program 15.6 sharedmemsum.cA function that keeps a synchronized sum and count in shared memory.
Each process must call initshared at least once before calling add or getcountandsum. A process may call initshared more than once, but one thread of the process should not call initshared while another thread of the same process is calling add or getcountandsum. Example 15.12In Program 15.6, the three fields of the shared memory segment are treated differently. The sum and count are explicitly initialized to 0 whereas the function relies on the fact that ready is initialized to 0 when the shared memory segment is created. Why is it done this way? Answer: All three fields are initialized to 0 when the shared memory segment is created, so in this case the explicit initialization is not necessary. The program relies on the atomic nature of the creation and initialization of ready to 0, but sum and count can be initialized to any values. Program 15.7 displays the shared count and sum when it receives a SIGUSR1 signal. The signal handler is allowed to use fprintf for output, even though it might not be async-signal safe, since no output is done by the main program after the signal handler is set up and the signal is unblocked. Program 15.8 modifies Program 15.5 by copying information from a single file to standard output and saving the number of bytes copied in a shared sum implemented by Program 15.6. Program 15.8 has two command-line arguments: the name of the file; and the key identifying the shared memory and its protecting semaphore. You can run multiple copies of Program 15.8 simultaneously with different filenames and the same key. The common shared memory stores the total number of bytes copied. Program 15.7 showshared.cA program to display the shared count and sum when it receives a SIGUSR1 signal.
Program 15.8 monitoroneshared.cA program to monitor one file and send the output to standard output. It keeps track of the number of bytes received by calling add from Program 15.6.
Example 15.13Start Program 15.7 in one window, using key 12345, with the following command.
Create a few named pipes, say, pipe1 and pipe2. Start copies of monitoroneshared in different windows with the following commands.
In other windows, send characters to the pipes (e.g., cat > pipe1). Periodically send SIGUSR1 signals to showshared to monitor the progress. |
[ Team LiB ] |
No comments:
Post a Comment