Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to use shared memory in CentOS

2025-02-22 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Servers >

Share

Shulou(Shulou.com)06/01 Report--

It is believed that many inexperienced people have no idea about how to use shared memory in CentOS. Therefore, this article summarizes the causes and solutions of the problem. Through this article, I hope you can solve this problem.

The so-called shared memory means that multiple processes can access the same memory space, which is the fastest available IPC form. It is designed for the low efficiency of other communication mechanisms. It is often used in conjunction with other communication mechanisms, such as semaphores, to achieve synchronization and mutual exclusion between processes. Other processes can "connect" the same shared memory segment to their own address space. All processes can access addresses in shared memory. If a process writes data to this shared memory, the changes will be immediately seen by other processes accessing the same shared memory. The use of shared memory greatly reduces the memory consumption in large-scale data processing, but there are many traps in the use of shared memory, which can easily lead to program crash if you don't pay attention to it.

The size limit of shared memory is exceeded?

On a linux server, the overall size of shared memory is limited, which is defined by the SHMMAX parameter (in bytes), and you can determine the value of SHMMAX by executing the following command:

# cat / proc/sys/kernel/shmmax

If the total size of shared memory created on the machine exceeds this limit, using standard error perror in your program may result in the following message:

Unable to attach to shared memory

Solution:

1. Set SHMMAX

The default value for SHMMAX is 32MB. Generally use one of the following methods to set the SHMMAX parameter to 2GB:

By directly changing the / proc file system, you can change the default settings of SHMMAX without restarting the machine. The method I use is to put the following command into the / > etc/rc.local startup file:

# echo "2147483648" > / proc/sys/kernel/shmmax

You can also use the sysctl command to change the value of SHMMAX:

# sysctl-w kernel.shmmax=2147483648

Finally, you can make this change permanent by inserting the kernel parameter into the / etc/sysctl.conf startup file:

# echo "kernel.shmmax=2147483648" > > / etc/sysctl.conf

2. Set SHMMNI

Let's now look at the SHMMNI parameter. This kernel parameter is used to set the maximum number of system-wide shared memory segments. The default value for this parameter is 4096. This number is sufficient and usually does not need to be changed.

You can determine the value of SHMMNI by executing the following command:

# cat / proc/sys/kernel/shmmni

4096

3. Set SHMALL

Finally, let's look at the SHMALL shared memory kernel parameters. This parameter controls the total amount of shared memory (in pages) that the system can use at a time. In short, the value of this parameter should always be at least:

Ceil (SHMMAX/PAGE_SIZE)

The default size of SHMALL is 2097152, and you can query using the following command:

# cat / proc/sys/kernel/shmall

2097152

The default setting of SHMALL should be sufficient for us.

Note: the page size of Red Hat Linux on the i386 platform is 4096 bytes. However, you can use bigpages, which supports the configuration of larger memory page sizes.

What is the problem with doing shmat multiple times?

When a shared memory segment is first created, it cannot be accessed by any process. In order for the shared memory area to be accessible, it must be attach to its own process space through the shmat function, so that the process establishes a connection to the shared memory. The function is declared in linux/shm.h:

# include

# include

Void * shmat (int shmid, const void * shmaddr, int shmflg)

The parameter shmid is the return value of shmget (), which is an identifier

The parameter shmflg is the access permission flag; if 0, no restricted permissions are set. Several permissions are defined in:

# define SHM_RDONLY 010000 / * attach read-only else read-write * /

# define SHM_RND 020000 / * round attach address to SHMLBA * /

# define SHM_REMAP 040000 / * take-over region on attach * /

If SHM_RDONLY is specified, the shared memory area has only read permissions.

Parameter shmaddr is an additional point of shared memory. Different values have different meanings:

? If it is empty, the kernel selects an idle memory area; if not, the return address depends on whether the caller specifies a SHM_RND value for the shmflg parameter, and if not, the shared memory area is appended to the address specified by shmaddr; otherwise, the additional address is the address (SHMLBA, a permanent address) after shmaddr rounds down a low-end boundary address of shared memory.

Usually, the parameter shmaddr is set to NULL.

When the shmat () call succeeds, it returns a pointer to the shared memory area, which allows you to access the shared memory area, or-1 if it fails.

The mapping relationship is shown in the following figure:

Figure 1.1 shared memory map

Where shmaddr represents the starting address of the block of memory in the virtual memory space when the physical memory space is mapped to the virtual memory space of the process. In use, because we generally do not know which addresses are not occupied in the process, it is not good to specify that the memory of the physical space should be mapped to the virtual memory address of the process. Generally, the kernel will specify it:

Void ptr = shmat (shmid, NULL,0)

It is no problem to mount a shared memory in this way if it is a single call, but a process can mount shmat to the same shared memory multiple times. The physical memory points to the same block. If shmaddr is NULL, the linear address space returned each time is different. And the number of references to this piece of shared memory will increase. That is, multiple blocks of linear space of the process will point to the same physical address. In this way, if the linear address of the process that has previously mounted this piece of shared memory is not dropped by shmdt, that is, the requested linear address is not released, the virtual memory space of the process will be consumed all the time, which may eventually cause the process linear space to be used up and cause the next shmat or other operations to fail.

Solution:

You can identify whether the shared memory is mounted for the first time by judging whether the requested shared memory pointer is empty, use it to mount it, and exit if not.

Void* ptr = NULL

...

If (NULL! = ptr)

Return

Ptr = shmat (shmid,ptr,0666)

Attached:

The function shmat maps the identification number shmid shared memory to the address space of the calling process, and the mapped address is determined by the parameters shmaddr and shmflg. The criteria are:

(1) if the parameter shmaddr is NULL, the system will automatically determine the first address where the shared memory is linked to the process space.

(2) if the parameter shmaddr is not NULL and the parameter shmflg does not specify the SHM_RND flag, the system will use the address shmaddr to link the shared memory.

(3) if the parameter shmaddr is not NULL and the parameter shmflg specifies the SHM_RND flag bit, the system aligns the address shmaddr and links the shared memory. The option SHM_RND means integer alignment, the constant SHMLBA represents a multiple of the low boundary address, and the formula "shmaddr-(shmaddr% SHMLBA)" means to move the address shmaddr to an integer multiple of the low boundary address.

When Shmget creates shared memory, when the key is the same, what will go wrong?

Shmget () is used to create a shared memory area or to access an existing shared memory area. This function is defined in the header file linux/shm.h. The prototype is as follows:

# include

# include

Int shmget (key_t key, size_t size, int shmflg)

The parameter key is the key value obtained by ftok ()

The parameter size specifies the size of memory in bytes

The parameter shmflg is the operation flag bit, and some of its macros are defined as follows:

IPC_CREATE: when calling shmget, the system compares this value with the key of other shared memory areas. If the same key exists, the shared memory area already exists, and the identifier of the shared memory area is returned at this time, otherwise, a new shared memory area is created and its identifier is returned.

IPC_EXCL: this macro must be used with IPC_CREATE, otherwise it doesn't make sense. When shmflg takes IPC_CREATE | IPC_EXCL, it means that-1 is returned if the memory area is found to exist, and the error code is EEXIST.

Note that when creating a new shared memory area, the value of size must be greater than 0; if you are accessing an existing memory shared area, set size to 0.

Generally speaking, when we create shared memory, we use shmget in a process to create shared memory.

Int shmid = shmget (key, size, IPC_CREATE | 0666)

In another process, use shmget and the same key to get the shared memory that has been created

Int shmid = shmget (key, size, IPC_CREATE | 0666)

If the key of the created process and the attached process are the same, but the corresponding size size is different, will the shmget fail?

The size of the shared memory that has been created can be adjusted, but the size of the shared memory that has been created can only be reduced, not increased.

Such as:

Shm_id = shmget (key,4194304,IPC_CREAT)

A 4m shared memory is created. If the shared memory is not deleted, we will use it again.

Shm_id = shmget (key,10485760,IPC_CREAT)

To create a 10m shared memory, using the standard error output will have the following error message:

Shmget error: Invalid argument

However, if we use:

Shm_id = shmget (key,3145728,IPC_CREAT)

To create a 3m-sized shared memory, no error message will be output, but the shared memory size will be modified to 3145728, which also shows that when using shared memory, key is used as the unique identification of shared memory, and the size of shared memory can not distinguish between shared memory.

What problems will this lead to?

When multiple processes can create shared memory, if the same situation occurs in key, and the size of shared memory that one process needs to create is smaller than that of another process, the process with large shared memory creates shared memory first, and the process with small shared memory creates shared memory, and the process with small shared memory will get the shared memory of large shared memory process. And modify the size and contents of its shared memory (note the comments below), which may cause large shared memory processes to crash.

Solution:

Method 1:

When all shared memory is created, create it with exclusivity, even with the IPC_EXCL tag:

Shmget (key, size,IPC_CREATE | IPC_EXCL)

When attaching the shared memory, use exclusive creation to determine whether the shared memory has been created, and handle the error if it has not been created. If it has been created, attach it:

Shmid = Shmget (key, size,IPC_CREATE | IPC_EXCL)

If (- 1! = shmid)

{

Printf ("error")

}

Shmid = Shmget (key, size,IPC_CREATE)

Method 2:

Although they all want their programs to agree on a unique key value with other programs in advance, it is not always possible because their programs cannot select a key value for a piece of shared memory. Therefore, set key to IPC_PRIVATE here, so that the operating system will ignore the key, create a new shared memory, specify a key value, and then return the shared memory IPC identifier ID. The identifier ID of this new shared memory can be told to other processes by deriving child processes or writing files or pipes after the shared memory is established, that is, this method does not use key to create shared memory, and the uniqueness is guaranteed by the operating system.

Does ftok necessarily produce a unique key value?

The system must specify an ID value when establishing IPC communications (such as message queues, shared memory). Typically, this id value is obtained through the ftok function.

The prototype of ftok is as follows:

Key_t ftok (char * pathname, int proj_id)

Pathname is the file name you specify, and proj_id is the subsequence number.

In a general UNIX implementation, the index node number of the file is taken out, preceded by a subsequence number to get the return value of key_t. If the index node number of the specified file is 65538, which is converted to 0 × 010002 in hexadecimal, and the proj_ id value you specified is 38 and converted to 0 × 26 in hexadecimal, the final key_t return value is 0 × 26010002.

The method to query the file index node number is: ls-I

However, when the rebuilt file is deleted, the Inode number is assigned by the operating system according to the usage of the file system at that time, so it is different from the original, so the index node number is also different.

The ftok function generates a unique key value for the IPC object based on the file (or directory) name specified by pathname and the number specified by the proj_id parameter. In practice, it is easy to understand that in the case of the same proj_id, as long as the file (or directory) name remains the same, you can ensure that the ftok returns a consistent key value. However, this understanding is not entirely correct and may lay a very obscure trap for application development. Because there is such a risk in the implementation of ftok, that is, in the time period when multiple processes accessing the same shared memory successively call the ftok function, if the file (or directory) specified by pathname is deleted and recreated, the file system will give the file (or directory) with the same name new I-node information, so although the ftok called by these processes can be returned normally, the key value is not guaranteed to be the same. The possible consequence is that these processes originally intended to access the same shared memory object, but because of their different key values, the shared memory pointed to by the process is no longer consistent; if these shared memory are created, no errors will be reported on the surface during the running of the application, but the purpose of data transfer through a shared memory object will not be achieved.

So if you want to make sure that the key_t value remains the same, either make sure that the ftok file is not deleted, or specify a fixed key_ t value without ftok.

If a file that generated the key_ t value has been deleted, there is a good chance that the shared memory key_t value you are using now will conflict with the key_ t value of another process, as in the following case:

Process 1 uses file 1 to ftok to generate key10000, and process 2 uses file 2 to ftok to generate key 11111. If both process 1 and process 2 need to download the file and update the contents of the file to shared memory, process 1 and 2 need to download the file first, then delete the previous shared memory, then use ftok to generate a new key, and then use this key to apply for new shared memory to load the new problem. But it is possible that file 2 is relatively large and slow to download, while file 1 is relatively small and slow to download. As both file 1 and file 2 have been modified, the file node number occupied by file 1 may be occupied before file 2. At this time, if the key generated by the ftok of downloaded file 1 is 11111, it will conflict with the shared memory of process 2 of whether or not 11111 key at this time, resulting in problems.

Solution:

Method 1:

In programs that download files, when you use ftok to get key for downloaded files, you need to take measures to avoid conflicts, such as using an exclusive way to obtain shared memory, and if it is not successful, add one operation to key, and then obtain shared memory until there is no conflict.

Method 2:

Before downloading the file, mv the previous file to "occupy" the file node number to prevent other shared memory from getting it when applying for key.

In addition:

When the creation process notifies other processes to connect, it is recommended not to use ftok to obtain Key, but to use file or inter-process communication.

The trap of shared memory deletion?

When the process ends using the shared memory area, the function shmdt is used to disconnect the shared memory area. The function is declared in sys/shm.h and its prototype is as follows:

# include

# include

Int shmdt (const void * shmaddr)

The parameter shmaddr is the return value of the shmat function.

When the process leaves the shared memory area, the shm_nattch in the data structure shmid_ds is subtracted by 1. However, the shared memory still exists, and only when shm_attch is 0, that is, no process is using the shared memory area, the shared memory area is deleted in the kernel. In general, when a process terminates, the shared memory area to which it is attached is automatically detached.

We adopted:

Int shmctl (int shmid, int cmd, struct shmid_ds * buf)

To delete the existing shared memory.

The first parameter, shmid, is the marker returned by shmget.

The second parameter, cmd, is the action to be performed. He can have three values:

Command description

IPC_STAT sets the value associated with shared memory for data reflection in the shmid_ds structure.

IPC_SET sets the value associated with shared memory to the value provided in the shmid_ds data structure if the process has the appropriate permissions.

IPC_RMID deletes the shared memory segment.

The third parameter, buf, is a pointer to a structure that contains shared memory mode and permissions, which can be deleted to 0 by default.

If shared memory has been disconnected from all processes accessing it, the system immediately deletes the identifier of shared memory and deletes the shared memory area and all related data structures after calling the IPC_ RMID subcommand

If there are still other processes that remain connected to the shared memory, the shared memory is not immediately deleted from the system when the IPC_ RMID subcommand is called, but is set to the IPC_PRIVATE state and marked as deleted (the dest field can be seen using the ipcs command); the shared memory will not eventually disappear from the system until all connections have been disconnected.

It is important to note that once the shared memory is deleted through shmctl, the shared memory will not accept any new connections, even if it still exists in the system! Therefore, you can be sure that it is safe to perform a delete operation if there is no new connection after the shared memory is deleted; otherwise, if a new connection still occurs after the delete operation, these connections may fail!

The difference between Shmdt and shmctl:

Shmdt is to detach the shared memory from the process space, so that the shmid in the process is invalid and cannot be used. But keep the space.

And shmctl (sid,IPC_RMID,0) is to delete shared memory, completely unavailable, free space.

After reading the above, have you mastered how to use shared memory in CentOS? If you want to learn more skills or want to know more about it, you are welcome to follow the industry information channel, thank you for reading!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Servers

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report