Unix/Linux Shared Memory Applications and traps

Source: Internet
Author: User

 

Shared Memory is a memory area reserved by the system for communication between multiple processes. The/proc/sys/kernel/directory records some restrictions on the shared memory, such as the maximum number of bytes in a shared memory area shmmax, shmmni, the maximum number of identifiers in the shared memory area, can be adjusted manually, but this is not recommended.

I. Application

The usage of shared memory mainly includes the following APIs: ftok (), shmget (), shmat (), shmdt (), and shmctl ().

1) Use the ftok () function to obtain an ID number.

Application description:
In IPC, we often use the value of key_t to create or open semaphores, share memory and message queue.

Function prototype:
Key_t ftok (const char * pathname, int proj_id );

Keys:
1) The pathname must exist in the system and be accessible by the process.
3) proj_id is an integer between 1 and. A typical value is an ASCII value.
When the execution is successful, a key_t value will be returned, otherwise-1 will be returned. We can use strerror (errno) to determine the specific error information.

Considering that the application system may be applied on different hosts, you can directly define a key instead of using ftok to obtain:
# Define ipckey 0x344378

2) shmget () is used to open/point to a shared memory function.

Application description:
Shmget () is used to obtain the ID of the shared memory area. If the specified shared area does not exist, a corresponding area is created.

Function prototype:
Int shmget (key_t key, size_t size, int shmflg );

The key_t key is the identifier of the shared memory. For inter-process communication of the parent-child relationship, this identifier is replaced by ipc_private. If there is no relationship between the two processes, use ftok () to calculate an identifier (or define one by yourself.

Int size is the memory size.
Int flag is the memory mode and permission ID.
The following values are recommended for the mode:
Ipc_creat new (if it has been created, the ID of the current shared memory is returned)
Ipc_excl and ipc_creat are used in combination. If a file has been created, an error is returned.
Then, the "Mode" and "permission ID" are calculated as "or" and used as the third parameter.
For example, ipc_creat | ipc_excl | 0640
In this example, "0666" indicates the permission ID. "4/2/1" indicates the read, write, and execute permissions respectively. "First 0" indicates the UID, and "first 6" (4 + 2) indicates the permission of the owner, the second 4 indicates the same group permission, and the third 0 indicates the permissions of others.
If this function succeeds, the ID of the shared memory is returned. If the function fails, the value-1 is returned.

I would like to say a few more about this function.
When creating shared memory, the shmflg parameter requires at least ipc_creat | permission ID. If only ipc_creat is used, the requested address is k = 0 xffffffff and cannot be used;
When obtaining the created shared memory, do not use ipc_creat for shmflg (only permission IDs when the shared memory is created, such as 0640). Otherwise, in some cases, for example, if you use ipcrm to delete shared memory, you can use this function and use the ipc_creat parameter to obtain the shared memory once (of course, the acquisition fails), even if you create the shared memory again, in this case, you must change the key to recreate the shared memory.

3) shmat () maps the memory area to the virtual address space of the process.

Function prototype:
Void * shmat (INT shmid, char * shmaddr, int shmflag );

Shmat () is a function used to allow the process to access a shared memory.
Int shmid is the ID of the shared memory.
Char * shmaddr is the starting address of the shared memory. If shmaddr is 0, the kernel will map the shared memory image to the selected location in the address space of the calling process. If shmaddr is not 0, the kernel will map the shared memory image to the location specified by shmaddr. Therefore, shmaddr is generally set to 0.
Int shmflag is the memory operation mode of the current process. If it is shm_rdonly, it is read-only mode. The other is the read/write mode.
If successful, this function returns the starting address of the shared memory. -1 is returned if the request fails.

4) The shmdt () function deletes the memory usage of this process. shmdt () is opposite to shmat () and is used to prohibit the process from accessing a shared memory.

Function prototype:
Int shmdt (char * shmaddr );
The char * shmaddr parameter is the starting address of the shared memory.
If the call succeeds, 0 is returned. -1 is returned if the request fails.

5) shmctl () controls the use of this shared memory

Function prototype:
Int shmctl (INT shmid, int cmd, struct shmid_ds * BUF );
Int shmid is the ID of the shared memory.
Int CMD is a control command with the following values:
Ipc_stat obtains the shared memory status.
Ipc_set changes the shared memory status
Ipc_rmid: delete shared memory
Struct shmid_ds * Buf is a struct pointer. In ipc_stat, the obtained status is placed in this struct. To change the shared memory status, use this struct.
Returned value: Success: 0
Failed:-1

Example program:

# Include <sys/IPC. h>
# Include <sys/SHM. h>
# Include <string. h>
# Include <stdio. h>
# Include <stdlib. h>

# Define ipckey 0x366378

Typedef struct {
Char Agen [10];
Unsigned char file_no;
} St_setting;

Int main (INT argc, char ** argv)
{
Int shm_id;
Key_t key;
St_setting * p_setting;

// Check whether the shared memory exists. If yes, delete it first.
Shm_id = shmget (ipckey, 1028,0640 );
If (shm_id! =-1)
{
P_setting = (st_setting *) shmat (shm_id, null, 0 );
If (p_setting! = (Void *)-1)
{
Shmdt (p_setting );
Shmctl (shm_id, ipc_rmid, 0 );
}
}

Shm_id = shmget (ipckey, 1028,0640 | ipc_creat | ipc_excl );
If (shm_id =-1)
{
Printf ("shmget error \ n ");
Return-1;
}
// Append this shared memory area to your memory segment
P_setting = (st_setting *) shmat (shm_id, null, 0 );

Strncpy (p_setting-> Agen, "jinyh", 10 );
Printf ("Agen: % s \ n", p_setting-> AGEN );

P_setting-> file_no = 1;
Printf ("file_no: % d \ n", p_setting-> file_no );

System ("IPCS-M"); // you can see information related to the shared memory of a process. nattch is 1.

// Delete this shared memory area from its memory segment
If (shmdt (p_setting) =-1)
Perror ("detach error ");

System ("IPCS-M"); // you can see information about the process associated with the shared memory. nattch is 0.

// Delete shared memory
If (shmctl (shm_id, ipc_rmid, null) =-1)
Perror ("delete error ");

// Exit (0 );

}

Note: When shared memory is used, the program exits. If you have not used shmctl () in the program to delete the shared memory, you must use the ipcrm command to delete the shared memory. If you don't care, it's always there.
The IPCS command and ipcrm command are briefly explained.

Obtain IPC information:
IPCS [-M |-q |-S]
-M outputs information about shared memory.
-Q: output information about Message Queue
-S outputs information about the semaphore.
% IPCS-m

Delete IPC
Ipcrm-M |-q |-s shm_id
% Ipcrm-M 105

2. traps (refer to http://www.ibm.com/developerworks/cn/aix/library/au-cn-sharemem)

1) ftok trap

When ftok is used to generate a key, if the pathname parameter of ftok specifies that the file is deleted and then rebuilt, the file system will assign the file (or directory) with the same name to the new I node information, therefore, although the ftok called by these processes can return normal results, the obtained key values cannot be the same.

2) 3. shmat problems in Aix

In the AIX system, there are restrictions on the use of various inter-process communication mechanisms of System V. Unlike other UNIX operating systems that configure resources for the IPC Mechanism, AIX uses different methods. In Aix, the upper limit of the IPC Mechanism is defined and cannot be configured. In terms of the shared memory mechanism, the following restrictions exist on AIX systems of version 4.2.1 and later:

For 64-bit processes, the same process can connect up to 268435456 shared memory segments;
For 32-bit processes, the same process can connect up to 11 shared memory segments, unless an extended shmat is used;
The above restrictions do not cause any trouble for 64-bit applications, because the number of connections available is large enough. However, for 32-bit applications, it is easy to cause unexpected problems, because the maximum number of connections is only 11.

The following routine test02.c demonstrates this problem. To streamline the code, it repeatedly connects to the same shared memory object. In fact, no matter whether the connected shared memory objects are the same, this limit limits the number of connections:

# Include <stdio. h>
# Include <errno. h>
# Include <sys/types. h>
# Include <sys/IPC. h>
# Include <sys/SHM. h>
# Define max_attach_num 15

Void main (INT argc, char * argv [])
{
Key_t mem_key;
Long mem_id;
Void * mem_addr [max_attach_num];
Int I;
If (mem_key = ftok ("/tmp/mykeyfile", 1) = (key_t) (-1 )){
Printf ("failed to generate shared memory access key, errno = % d \ n ",
Errno );
Goto mod_exit;
}
If (mem_id = shmget (mem_key, 256, ipc_creat) = (-1 )){
Printf ("failed to obtain shared memory ID, errno = % d \ n", errno );
Goto mod_exit;
}
For (I = 1; I <= max_attach_num; I ++ ){
If (mem_addr [I] = (void *) shmat (mem_id, 0, 0) = (void *) (-1 ))
Printf ("failed to attach shared memory, times [% 02d], errno: % d \ n", I,
Errno );
Else
Printf ("successfully attached shared memory, times [% 02d] \ n", I );
}
Mod_exit:
Shmctl (mem_id, ipc_rmid, null );
}

On the AIX system, we compile it into test02 and run it. The following output is displayed:

Successfully attached shared memory, times [01]
Successfully attached shared memory, times [02]
Successfully attached shared memory, times [03]
Successfully attached shared memory, times [04]
Successfully attached shared memory, times [05]
Successfully attached shared memory, times [06]
Successfully attached shared memory, times [07]
Successfully attached shared memory, times [08]
Successfully attached shared memory, times [09]
Successfully attached shared memory, times [10]
Successfully attached shared memory, times [11]
Failed to attach shared memory, times [12], errno: 24
Failed to attach shared memory, times [13], errno: 24
Failed to attach shared memory, times [14], errno: 24
Failed to attach shared memory, times [15], errno: 24

It indicates that after 11 connections are exceeded, all subsequent shared memory Connections cannot be established. The error code 24 is defined as emfile, And Aix interprets it:

The number of shared memory segments attached to the calling process exceeds the system-imposed limit.

To solve this problem, use the extended shmat. Specifically, before running the application (specifically, before the shared memory is created ), first, set the extshm environment variable in the shell and use it to extend the shmat. You do not need to make any changes to the source code itself:

Export extshm = on

It is worth noting that although environment variables can be set, the setenv function can also be used in the program. For example, add the following code at the beginning of the program:

Setenv ("extshm", "on", 1 );

However, practice has proved that this method is ineffective in solving this problem. That is to say, the only feasible method is to set the extshm environment variable in the shell, rather than in the program.

When configuring a 32-bit DB2 instance on AIX, make sure that the environment variable extshm is set to on, which is required before running Warehouse Manager and query patroller:
Export extshm = on
Db2set db2envlist = extshm
Db2start
This is because the maximum number of connections exists when we connect 32-bit applications in Aix to the shared memory. This problem also exists in Oracle and other software products on the AIX platform.

3) shmget and shmat in HP-UX

3.1 32-bit and 64-bit application compatibility

On the HP-UX platform, if 32-bit and 64-bit applications run simultaneously and they access the same shared memory zone, there will be compatibility issues.

In the HP-UX, the application sets the ipc_creat flag to call shmget, the created shared memory zone, which can only be accessed by applications of the same type; that is, the shared memory area created by a 32-bit application can only be accessed by other 32-bit applications. Similarly, the shared memory area created by a 64-bit application can only be accessed by other 64-bit applications.

If a 32-bit application attempts to access a shared memory area created by a 64-bit application, it will fail to call shmget and get the einval error code. The explanation is:

A shared memory identifier exists for key but is in 64-bit address space and the process implements the request has been compiled as a 32-bit executable.

To solve this problem, when a 64-bit application creates shared memory, the ipc_creat flag is merged and the ipc_1_32 flag is also given:

Shmget (mem_key, size, 0666 | ipc_creat | ipc_rj32)

For 32-bit applications, the ipc_1_32 flag is not required, but setting this flag does not cause any problems, that is, whether the application is compiled into the 32-bit or 64-Bit mode, the same Code can be used, and the compatibility between 32-bit applications and 64-bit applications on shared memory access is solved.

3.2 limit on the number of connections to the same shared memory

On a HP-UX, application processes are limited to up to one connection to the same shared memory zone; different from the number of connections on AIX described in section 3rd above, the HP-UX does not set an upper limit on the number of connections pointing to different shared memory zones, that is, the application processes running on the HP-UX can connect to multiple different shared memory zones at the same time, however, for the same shared memory area, only one connection is allowed. Otherwise, the shmat call fails and the error code einval is returned. In the shmat man help, the error code is described as follows:

Shmid is not a valid shared memory identifier, (possibly because the shared memory segment was already removed using shmctl (2) with ipc_rmid), or the calling process is already attached to shmid.

This restriction will cause unavoidable problems for multi-threaded applications. As long as more than one thread in an application process attempts to connect to the same shared memory zone, it will all end with a failure.

To solve this problem, you need to modify the application design so that the application process can access the same shared memory with multiple threads. Compared with the preceding solution, the solution to this problem is more complex.

As one of the methods for reference, the logic described below can solve this problem well:

The basic idea is to set the key value (returned value of ftok) and system identifier (returned value of shmid and shmget call) after the application process connects to each shared memory zone for the first time) and the access address (that is, the return value of the shmat call) are saved, and records are left in the form of a global array or linked list of the process. Before any connection to the shared memory, the program will first retrieve this record list and match the shared memory to be accessed based on the key value and identifier. If a matching record is found, then, the access address is directly read from the record without calling the shmat function again to solve this problem. If no matching target is found, the shmat function is called to establish a connection, add a new record for the shared memory of the new connection.

The data structure of the record entry, which can be defined as follows:

Typedef struct _ shared_memory_record
{
Key_t mem_key; // key generated by ftok ()
Int mem_id; // ID returned by shmget ()
Void * mem_addr; // access address returned by shmat ()
Int nattach; // times of attachment
} Shared _

4) shmdt function prototype in Solaris

Shmdt calls in the Solaris system are different from the System V standard in prototype,

Default
Int shmdt (char * shmaddr );

That is, the shmaddr data type is char * on Solaris, while System V defines the void * type. In fact, on Solaris, The shmdt call follows the function prototype specification which is the standard before the SVID-v4; taking Linux as an example, libc4 and libc5 adopt char * type parameters, while glibc2 following the SVID-v4 and subsequent standard and its updated version are changed to void * type parameters.

If the system V standard prototype is still used in the code, compilation errors will occur during code compilation on Solaris. For example:

Error: formal argument 1 of type char * in call to shmdt (char *)
Is being passed void *.

The solution is to introduce a Conditional compilation macro. When the compiling platform is Solaris, char * type parameters are used, the System V standard void * type parameters are still used, for example:

# Ifdef _ solaris_shared_memory
Shmdt (char *) mem_addr );
# Else
Shmdt (void *) mem_addr );
# Endif

5) Risks of deleting shared memory through shmctl

If the shared memory has been disconnected from all the processes that access it, the system will immediately delete the identifier of the shared memory after calling the ipc_rmid sub-command and delete the shared memory zone, and all relevant data structures;
If another process is still connected to the shared memory, the shared memory will not be immediately deleted from the system but set to ipc_private after the ipc_rmid sub-command is called, and marked as "deleted". The shared memory will not disappear from the system until all existing connections are disconnected.

It should be noted that once the shared memory is deleted through shmctl, the shared memory will no longer accept any new connections, even if it still exists in the system! Therefore, it is clear that it is safe to delete a new connection after the shared memory is deleted. Otherwise, if a new connection still occurs after the delete operation, all these connections will fail!

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.