This sharing of memory provides the fastest means of exchanging data between processes.
A process initially creates a shared memory segment facility using the shmget() system call. Arguments to this function set the overall operation permissions for the shared memory segment facility, sets its size in bytes, and can specify that the shared memory segment is for reference only (read-only) upon attachment. If the memory segment is not specified to be for reference only, all other processes with appropriate operation permissions can read from or write to the memory segment.
There are two operations that can be performed on a shared memory segment:
Shared memory detach allows processes to disassociate themselves from a shared memory segment. Therefore, they lose the ability to read from or write to the shared memory segment.
The original owner/creator of a shared memory segment can relinquish ownership to another process using the shmctl() system call. However, the creating process remains the creator until the facility is removed or the system is reinitialized. Other processes with permission can perform other functions on the shared memory segment using the shmctl() system call.
System calls, documented in the IRIX reference pages, make these shared memory capabilities available to processes. The calling process passes arguments to a system call, and the system call attempts to perform its function. If the system call is successful, it performs its function and returns the appropriate information. Otherwise, a known error code (-1) is returned to the process, and the external variable errno is set accordingly.
Before memory sharing can be realized, a uniquely identified shared memory segment and data structure must be created. The unique identifier created is called the shared memory identifier (shmid); it is used to identify or reference the associated data structure. The data structure includes the following for each shared memory segment:
struct shmid_ds { struct ipc_perm shm_perm; /* operation permission struct */ int shm_segsz; /* segment size */ struct region *shm_reg; /* ptr to region structure */ char pad[4]; /* for swap compatibility */ ushort shm_lpid; /* pid of last shmop */ ushort shm_cpid; /* pid of creator */ ushort shm_nattch; /* used only for shminfo */ ushort shm_cnattch; /* used only for shminfo */ time_t shm_atime; /* last shmat time */ time_t shm_dtime; /* last shmdt time */ time_t shm_ctime; /* last change time */ };Note that the shm_perm member of this structure uses ipc_perm as a template. The ipc_perm data structure is the same for all IPC facilities, and is located in the /usr/include/sys/ipc.h header file.
The shmget() system call is used to perform two tasks when only the IPC_CREAT flag is set in the shmflg argument that it receives:
A provision exists for specifying a key of value zero, known as the private key (IPC_PRIVATE = 0); when specified, a new shmid is always returned with an associated shared memory segment data structure created for it unless a system tuning parameter would be exceeded. When the ipcs command is performed, the KEY field for the shmid is all zeros.
For the second task, if a shmid exists for the key specified, the value of the existing shmid is returned. If you do not want to have an existing shmid returned, a control command (IPC_EXCL) can be set in the shmflg argument passed to the system call. The details of using this system call are discussed in "Getting Shared Memory Segments With shmget()."
When performing the first task, the process that calls shmget() becomes the owner/creator, and the associated data structure is initialized accordingly. Remember, ownership can be changed, but the creating process always remains the creator; see "Controlling Shared Memory: shmctl()." The creator of the shared memory segment also determines the initial operation permissions for it.
Once a uniquely identified shared memory segment data structure is created, shared memory segment operations and control can be used.
Shared memory segment operations consist of attaching and detaching shared memory segments. System calls are provided for each of these operations; they are shmat() and shmdt(). Refer to "Operations for Shared Memory: shmat() and shmdt()" for details of these system calls.
Shared memory segment control is done by using the shmctl() system call. It permits you to control the shared memory facility in the following ways:
The prototype found in the shmget(2) reference page is as follows:
The integer returned from this function upon successful completion is the shared memory identifier (shmid) that was discussed earlier.int shmget (key_t key, size_t size, int shmflg);
A new shmid with an associated shared memory data structure is provided when either of the following conditions is true:
Access permissions determine the read/write attributes, and execution modes determine the user/group/other attributes of the shmflg argument. They are collectively referred to as "operation permissions." Table 2-6 shows the numeric values (expressed in octal notation) for the valid operation permissions codes.
Operation Permissions | Octal Values |
---|---|
Read by User | 00400 |
Write by User | 00200 |
Read by Group | 00040 |
Write by Group | 00020 |
Read by Others | 00004 |
Write by Others | 00002 |
A specific octal value is derived by adding the octal values for the operation permissions desired. That is, if read by user and read/write by others are desired, the code value would be 00406 (00400 plus 00004 plus 00002).
Constants located in the shm.h header file can be used for the owner. They include:
Control command constants are predefined in the ipc.h header file. Table 2-7 contains the names of the constants that apply to the shmget() system call along with their values.SHM_R 0400
SHM_W 0200
Control | Value |
---|---|
IPC_CREAT | 0001000 |
IPC_EXCL | 0002000 |
The value for shmflg is a combination of operation permissions and control commands, usually an expression using bitwise OR (|) with the operation permissions.
As specified by the shmget(2) reference page, success or failure of this system call depends upon the argument values for key, size, and shmflg, and on system tuning parameters. The system call attempts to return a new shmid if one of the following conditions is true:shmid = shmget (key, size, (IPC_CREAT | 0400));
shmid = shmget (key, size, (IPC_CREAT | IPC_EXCL | 0400));
IPC_EXCL is another control command used with IPC_CREAT to exclusively have the system call fail if, and only if, a shmid exists for the specified key provided. This is necessary to prevent the process from thinking that it has received a new (unique) shmid when it has not. In other words, when both IPC_CREAT and IPC_EXCL are specified, a unique shmid is returned if the system call is successful. Any value for shmflg returns a new shmid if the key equals zero (IPC_PRIVATE).
The system call fails if the value for the size argument is less than SHMMIN or greater than SHMMAX. These tunable parameters specify the minimum and maximum shared memory segment sizes.
Refer to the shmget(2) reference page for specific associated data structure initialization for successful completion. The specific failure conditions with error names are contained there also.
Variable names have been chosen to be as close as possible to those in the synopsis for the system call. Their declarations are self-explanatory. These names make the program more readable, and this is perfectly legal since they are local to the program. The variables declared for this program and their purposes are as follows:
key | The desired semaphore key |
opperm | The desired operation permissions |
flags | The desired control commands (flags) |
opperm_flags | The combination from the logical ORing of the opperm and flags variables, used in the system call to pass the shmflg argument |
shmid | The message queue identification number from a successful system call or the error code (-1) for an unsuccessful one |
size | The shared memory segment size |
The program begins by prompting for a hexadecimal key, an octal operation permissions code, and finally for the control command combinations (flags), which are selected from a menu (lines 14-31). All possible combinations are allowed even though they might not be viable. Thus you can observe the errors for illegal combinations.
Next, the menu selection for the flags is combined with the operation permissions, and the result is stored in the opperm_flags variable (lines 35-50).
A display then prompts for the size of the shared memory segment, which is stored in the size variable (lines 51-54).
The system call is made next, and the result is stored in the shmid variable (line 56).
Since the shmid variable now contains a valid message queue identifier or the error code (-1), it is tested to see if an error occurred (line 58). If shmid equals -1, a message indicates that an error resulted and the external errno variable is displayed (lines 60, 61). If no error occurred, the returned shared memory segment identifier is displayed (line 65).
Example 2-10 : shmget() System Call Example
1 /*This is a program to illustrate 2 *the shared memory get, shmget(), 3 *system call capabilities.*/ 4 #include <sys/types.h> 5 #include <sys/ipc.h> 6 #include <sys/shm.h> 7 #include <errno.h> 8 /*Start of main C language program*/ 9 main() 10 { 11 key_t key; /*declare as long integer*/ 12 int opperm, flags; 13 int shmid, size, opperm_flags; 14 /*Enter the desired key*/ 15 printf("Enter the desired key in hex = "); 16 scanf("%x", &key); 17 /*Enter the desired octal operation 18 permissions.*/ 19 printf("\nEnter the operation\n"); 20 printf("permissions in octal = "); 21 scanf("%o", &opperm); 22 /*Set the desired flags.*/ 23 printf("\nEnter corresponding number to\n"); 24 printf("set the desired flags:\n"); 25 printf("No flags = 0\n"); 26 printf("IPC_CREAT = 1\n"); 27 printf("IPC_EXCL = 2\n"); 28 printf("IPC_CREAT and IPC_EXCL = 3\n"); 29 printf(" Flags = "); 30 /*Get the flag(s) to be set.*/ 31 scanf("%d", &flags); 32 /*Check the values.*/ 33 printf ("\nkey =0x%x, opperm = 0%o, flags = 0%o\n", 34 key, opperm, flags); 35 /*Incorporate the control fields (flags) with 36 the operation permissions*/ 37 switch (flags) 38 { 39 case 0: /*No flags are to be set.*/ 40 opperm_flags = (opperm | 0); 41 break; 42 case 1: /*Set the IPC_CREAT flag.*/ 43 opperm_flags = (opperm | IPC_CREAT); 44 break; 45 case 2: /*Set the IPC_EXCL flag.*/ 46 opperm_flags = (opperm | IPC_EXCL); 47 break; 48 case 3: /*Set the IPC_CREAT and IPC_EXCL flags.*/ 49 opperm_flags = (opperm | IPC_CREAT | IPC_EXCL); 50 } 51 /*Get the size of the segment in bytes.*/ 52 printf ("\nEnter the segment"); 53 printf ("\nsize in bytes = "); 54 scanf ("%d", &size); 55 /*Call the shmget system call.*/ 56 shmid = shmget (key, size, opperm_flags); 57 /*Perform the following if the call is unsuccessful.*/ 58 if(shmid == -1) 59 { 60 printf ("\nThe shmget system call failed!\n"); 61 printf ("The error number = %d\n", errno); 62 } 63 /*Return the shmid upon successful completion.*/ 64 else 65 printf ("\nThe shmid = %d\n", shmid); 66 exit(0); 67 }
The prototype found in the shmctl(2) reference page is as follows:
The shmctl() system call requires two or three arguments to be passed to it, and it returns an integer value. Upon successful completion, a zero value is returned; when unsuccessful, shmctl() returns a -1.int shmctl (int shmid, int cmd [, struct shmid_ds *buf] );
The shmid variable must be a nonnegative integer returned by shmget(). The cmd argument can be replaced by one of following control commands (flags):
IPC_STAT | Return the status information contained in the associated data structure for the specified shmid and place it in the data structure pointed to by the buf pointer in the user memory area. |
IPC_SET | For the specified shmid, set the effective user and group identification, and operation permissions. |
IPC_RMID | Remove the specified shmid along with its associated shared memory segment data structure. |
SHM_LOCK | Lock the specified shared memory segment in memory; must be super user. |
SHM_UNLOCK | Unlock the shared memory segment from memory; must be super user. |
A process must have the effective user identification of the owner/creator of the segment, or of superuser, to perform an IPC_SET or IPC_RMID control command. Only the superuser can perform a SHM_LOCK or SHM_UNLOCK control command. A process must have read permission to perform the IPC_STAT control command.
The details of this system call are discussed in the example program for it. If you have problems understanding the logic manipulations in this program, read "Getting Shared Memory Segments With shmget()"; it goes into more detail than would be practical to do for every system call.
This program begins (lines 5-9) by including the required header files as specified by the shmctl(2) reference page. Note in this program that errno is declared as an external variable, and therefore, the errno.h header file does not have to be included.
Variable and structure names have been chosen to be as close as possible to those in the synopsis for the system call. Their declarations are self-explanatory. These names make the program more readable, and it is perfectly legal since they are local to the program. The variables declared for this program and their purposes are as follows:
uid | The IPC_SET value for the effective user identification. |
gid | The IPC_SET value for the effective group identification. |
mode | The IPC_SET value for the operation permissions. |
rtrn | The return integer value from the system call. |
shmid | The shared memory segment identifier to the system call. |
command | The code for the desired control command so that subsequent processing can be performed on it. |
choice | Which member for the IPC_SET control command is to be changed. |
shmid_ds | The data structure returned from an IPC_STAT control command. |
buf | Address of the data structure in the user memory area where IPC_STAT is to place its return values or where the IPC_SET command gets the values to set. |
Note that the shmid_ds data structure in this program (line 16) uses the data structure located in the shm.h header file of the same name as a template for its declaration. This is a perfect example of the advantage of local variables.
The next important thing to observe is that although the *buf pointer is declared to be a pointer to a data structure of the shmid_ds type, it must also be initialized to contain the address of the user memory area data structure (line 17).
First, the program prompts for a valid shared memory segment identifier that is stored in the shmid variable (lines 18-20). This is required for every shmctl() system call.
Then, the code for the desired control command must be entered (lines 21-29), and it is stored in the command variable. The code is tested to determine the control command for subsequent processing.
If the IPC_STAT control command is selected (code 1), the system call is performed (lines 39, 40) and the status information returned is printed out (lines 41-71). Note that if the system call is unsuccessful (line 146), the status information of the last successful call is printed out. In addition, an error message is displayed and the errno variable is printed out (lines 148, 149). If the system call is successful, a message indicates this along with the shared memory segment identifier used (lines 151-154).
If the IPC_SET control command is selected (code 2), the first thing done is to get the current status information for the message queue identifier specified (lines 90-92). This is necessary because this example program provides for changing only one member at a time, and the system call changes all of them. Also, if an invalid value happened to be stored in the user memory area for one of these members, it would cause repetitive failures for this control command until corrected. The next thing the program does is to prompt for a code corresponding to the member to be changed (lines 93-98). This code is stored in the choice variable (line 99). Now, depending upon the member picked, the program prompts for the new value (lines 105-127). The value is placed in the appropriate member in the user memory area data structure, and the system call is made (lines 128-130). Depending upon success or failure, the program returns the same messages as for IPC_STAT above.
If the IPC_RMID control command (code 3) is selected, the system call is performed (lines 132-135), and the shmid along with its associated message queue and data structure are removed from the UNIX operating system. Note that the *buf pointer is not required as an argument to perform this control command and its value can be zero or NULL. Depending upon the success or failure, the program returns the same messages as for the other control commands.
If the SHM_LOCK control command (code 4) is selected, the system call is performed (lines 137,138). Depending upon the success or failure, the program returns the same messages as for the other control commands.
If the SHM_UNLOCK control command (code 5) is selected, the system call is performed (lines 140-142). Depending upon the success or failure, the program returns the same messages as for the other control commands.
Example 2-11 : shmctl() System Call Example
1 /*This is a program to illustrate 2 *the shared memory control, shmctl(), 3 *system call capabilities. 4 */ 5 /*Include necessary header files.*/ 6 #include <stdio.h> 7 #include <sys/types.h> 8 #include <sys/ipc.h> 9 #include <sys/shm.h> 10 /*Start of main C language program*/ 11 main() 12 { 13 extern int errno; 14 int uid, gid, mode; 15 int rtrn, shmid, command, choice; 16 struct shmid_ds shmid_ds, *buf; 17 buf = &shmid_ds; 18 /*Get the shmid, and command.*/ 19 printf("Enter the shmid = "); 20 scanf("%d", &shmid); 21 printf("\nEnter the number for\n"); 22 printf("the desired command:\n"); 23 printf("IPC_STAT = 1\n"); 24 printf("IPC_SET = 2\n"); 25 printf("IPC_RMID = 3\n"); 26 printf("SHM_LOCK = 4\n"); 27 printf("SHM_UNLOCK = 5\n"); 28 printf("Entry = "); 29 scanf("%d", &command); 30 /*Check the values.*/ 31 printf ("\nshmid =%d, command = %d\n", 32 shmid, command); 33 switch (command) 34 { 35 case 1: /*Use shmctl() to duplicate 36 the data structure for 37 shmid in the shmid_ds area pointed 38 to by buf and then print it out.*/ 39 rtrn = shmctl(shmid, IPC_STAT, 40 buf); 41 printf ("\nThe USER ID = %d\n", 42 buf->shm_perm.uid); 43 printf ("The GROUP ID = %d\n", 44 buf->shm_perm.gid); 45 printf ("The creator's ID = %d\n", 46 buf->shm_perm.cuid); 47 printf ("The creator's group ID = %d\n", 48 buf->shm_perm.cgid); 49 printf ("The operation permissions = 0%o\n", 50 buf->shm_perm.mode); 51 printf ("The slot usage sequenceen"); 52 printf ("number = 0%x\n", 53 buf->shm_perm.seq); 54 printf ("The key= 0%x\n", 55 buf->shm_perm.key); 56 printf ("The segment size = %d\n", 57 buf->shm_segsz); 58 printf ("The pid of last shmop = %d\n", 59 buf->shm_lpid); 60 printf ("The pid of creator = %d\n", 61 buf->shm_cpid); 62 printf ("The current # attached = %d\n", 63 buf->shm_nattch); 64 printf("The in memory # attached = %d\n", 65 buf->shm_cnattach); 66 printf("The last shmat time = %d\n", 67 buf->shm_atime); 68 printf("The last shmdt time = %d\n", 69 buf->shm_dtime); 70 printf("The last change time = %d\n", 71 buf->shm_ctime); 72 break; /* Lines 73 - 87 deleted */ 88 case 2: /*Select and change the desired 89 member(s) of the data structure.*/ 90 /*Get the original data for this shmid 91 data structure first.*/ 92 rtrn = shmctl(shmid, IPC_STAT, buf); 93 printf("\nEnter the number for the\n"); 94 printf("member to be changed:\n"); 95 printf("shm_perm.uid = 1\n"); 96 printf("shm_perm.gid = 2\n"); 97 printf("shm_perm.mode = 3\n"); 98 printf("Entry = "); 99 scanf("%d", &choice); 100 /*Only one choice is allowed per 101 pass as an illegal entry will 102 cause repetitive failures until 103 shmid_ds is updated with 104 IPC_STAT.*/ 105 switch(choice){ 106 case 1: 107 printf("\nEnter USER ID = "); 108 scanf ("%d", &uid); 109 buf->shm_perm.uid = uid; 110 printf("\nUSER ID = %d\n", 111 buf->shm_perm.uid); 112 break; 113 case 2: 114 printf("\nEnter GROUP ID = "); 115 scanf("%d", &gid); 116 buf->shm_perm.gid = gid; 117 printf("\nGROUP ID = %d\n", 118 buf->shm_perm.gid); 119 break; 120 case 3: 121 printf("\nEnter MODE = "); 122 scanf("%o", &mode); 123 buf->shm_perm.mode = mode; 124 printf("\nMODE = 0%o\n", 125 buf->shm_perm.mode); 126 break; 127 } 128 /*Do the change.*/ 129 rtrn = shmctl(shmid, IPC_SET, 130 buf); 131 break; 132 case 3: /*Remove the shmid along with its 133 associated 134 data structure.*/ 135 rtrn = shmctl(shmid, IPC_RMID, NULL); 136 break; 137 case 4: /*Lock the shared memory segment*/ 138 rtrn = shmctl(shmid, SHM_LOCK, NULL); 139 break; 140 case 5: /*Unlock the shared memory 141 segment.*/ 142 rtrn = shmctl(shmid, SHM_UNLOCK, NULL); 143 break; 144 } 145 /*Perform the following if the call fails.*/ 146 if(rtrn == -1) 147 { 148 printf ("\nThe shmctl system call failed!\n"); 149 printf ("The error number = %d\n", errno); 150 } 151 /*Return the shmid upon successful completion.*/ 152 else 153 printf ("\nShmctl was successful for shmid = %d\n", 154 shmid); 155 exit (0); 156 }
The prototypes found in the shmop(2) reference page, which includes both shmat() and shmaddr(), are as follows:
Attaching to a Shared Memory Segmentvoid *shmat(int shmid, void *shmaddr, int shmflg); int shmdt (void *shmaddr);
The shmat() system call takes three arguments and it returns a character pointer value. The returned value can be cast to an integer value. Upon successful completion, this value is the address in memory where the process is attached to the shared memory segment, and when unsuccessful, it is -1.
The shmid argument must be a nonnegative integer returned from shmget(). The shmaddr argument can be 0 or nonzero. When it is 0 , IRIX picks the address of the shared segment. When shmaddr is nonzero it must be a valid address that IRIX would pick. It is wise to let the operating system pick addresses so as to improve portability.
The shmflg argument passes the SHM_RND and SHM_RDONLY flags to shmat().
Detaching Shared Memory Segments
The shmdt() system call takes one argument and returns an integer value, 0 if it completes successfully, otherwise -1. Further details of this system call are discussed in the example program.
Example Program
The example program in Example 2-12 is a menu-driven program that exercises all possible combinations of the shmat() and shmdt() system calls.
This program begins (lines 5-9) by including the required header files as specified by the shmop(2) reference page. Note that in this program, errno is declared as an external variable, and therefore, the errno.h header file does not have to be included.
Variable and structure names were chosen to be as close as possible to those in the synopsis. Their declarations are self-explanatory. The names make the program more readable; this is legal since they are local to the program. The variables declared for this program and their purposes include:
flags | The codes of SHM_RND or SHM_RDONLY for the shmat() system call |
addr | The address of the shared memory segment for the shmat() and shmdt() system calls |
i | A loop counter for attaching and detaching |
attach | The desired number of attach operations |
shmid | The desired shared memory segment identifier |
shmflg | The value of flags to the shmat() system call |
rtrn | The return values from both system calls |
detach | The desired number of detach operations |
This example program combines both the shmat() and shmdt() system calls. The program prompts for the number of attachments, and enters a loop until they are done, for the specified shared memory identifiers. Then, the program prompts for the number of detachments to be performed, and enters a loop until they are done, for the specified shared memory segment addresses.
Example Use of shmat()
The program prompts for the number of attachments to be performed, and the value is stored in the attach variable (lines 17-21).
A loop is entered using the attach variable and the i counter (lines 23-70) to perform the specified number of attachments. In this loop, the program prompts for a shared memory segment identifier (lines 24-27) and it is stored in the shmid variable (line 28). Next, the program prompts for the address where the segment is to be attached (lines 30-34), and it is stored in the addr variable (line 35). Then, the program prompts for the desired flags to be used for the attachment (lines 37-44), and the code representing the flags is stored in the flags variable (line 45). The flags variable is tested to determine the code to be stored for the shmflg variable used to pass them to the shmat() system call (lines 46-57). The system call is made (line 60). If the call succeeds, a message stating so is displayed along with the attach address (lines 66-68). If the call is unsuccessful, a message stating so is displayed and the error code is displayed (lines 62, 63). The loop then continues.
Example Use of shmdt
After the attach loop completes, the program prompts for the number of detach operations to be performed (lines 71-75), and the value is stored in the detach variable (line 76).
A loop is entered using the detach variable and the i counter (lines 78-95) to perform the specified number of detachments. In this loop, the program prompts for the address of the shared memory segment to be detached (lines 79-83), and it is stored in the addr variable (line 84). Then, the shmdt() system call is performed (line 87). If the call succeeeds, a message stating so is displayed along with the address that the segment was detached from (lines 92,93). When the call is unsuccessful, the error number is displayed (line 89). The loop continues.
Example 2-12 : shmat() and shmdt() System Call Example
1 /*This is a program to illustrate 2 *the shared memory operations, shmop(), 3 *system call capabilities. 4 */ 5 /*Include necessary header files.*/ 6 #include <stdio.h> 7 #include <sys/types.h> 8 #include <sys/ipc.h> 9 #include <sys/shm.h> 10 /*Start of main C language program*/ 11 main() 12 { 13 extern int errno; 14 int flags, addr, i, attach; 15 int shmid, shmflg, retrn, detach; 16 /*Loop for attachments by this process.*/ 17 printf("Enter the number ofen"); 18 printf("attachments for this\n"); 19 printf("process (1-4).\n"); 20 printf(" Attachments = "); 21 scanf("%d", &attach); 22 printf("Number of attaches = %d\n", attach); 23 for(i = 1; i <= attach; i++) { 24 /*Enter the shared memory ID.*/ 25 printf("\nEnter the shmid ofen"); 26 printf("the shared memory segment to\n"); 27 printf("be operated on = "); 28 scanf("%d", &shmid); 29 printf("\nshmid = %d\n", shmid); 30 /*Enter the value for shmaddr.*/ 31 printf("\nEnter the value for\n"); 32 printf("the shared memory address\n"); 33 printf("in hexadecimal:\n"); 34 printf(" Shmaddr = "); 35 scanf("%x", &addr); 36 printf("The desired address = 0x%x\n", addr); 37 /*Specify the desired flags.*/ 38 printf("\nEnter the corresponding\n"); 39 printf("number for the desireden"); 40 printf("flags:\n"); 41 printf("SHM_RND = 1\n"); 42 printf("SHM_RDONLY = 2\n"); 43 printf("SHM_RND and SHM_RDONLY = 3\n"); 44 printf(" Flags = "); 45 scanf("%d", &flags); 46 switch(flags) 47 { 48 case 1: 49 shmflg = SHM_RND; 50 break; 51 case 2: 52 shmflg = SHM_RDONLY; 53 break; 54 case 3: 55 shmflg = SHM_RND | SHM_RDONLY; 56 break; 57 } 58 printf("\nFlags = 0%o\n", shmflg); 59 /*Do the shmat system call.*/ 60 retrn = (int)shmat(shmid, addr, shmflg); 61 if(retrn == -1) { 62 printf("\nShmat failed. "); 63 printf("Error = %d\n", errno); 64 } 65 else { 66 printf ("\nShmat was successful\n"); 67 printf("for shmid = %d\n", shmid); 68 printf("The address = 0x%x\n", retrn); 69 } 70 } 71 /*Loop for detachments by this process.*/ 72 printf("Enter the number ofen"); 73 printf("detachments for this\n"); 74 printf("process (1-4).\n"); 75 printf(" Detachments = "); 76 scanf("%d", &detach); 77 printf("Number of attaches = %d\n", detach); 78 for(i = 1; i <= detach; i++) { 79 /*Enter the value for shmaddr.*/ 80 printf("\nEnter the value for\n"); 81 printf("the shared memory address\n"); 82 printf("in hexadecimal:\n"); 83 printf(" Shmaddr = "); 84 scanf("%x", &addr); 85 printf("The desired address = 0x%x\n", addr); 86 /*Do the shmdt system call.*/ 87 retrn = (int)shmdt(addr); 88 if(retrn == -1) { 89 printf("Error = %d\n", errno); 90 } 91 else { 92 printf ("\nShmdt was successful\n"); 93 printf("for address = 0%x\n", addr); 94 } 95 } 96 }
Surveys the different facilities available for programming parallel computations, comparing the advantages of each.