POSIX共享内存对象是一种允许多个进程共享一个给定名称的内存区域的机制。这些共享内存对象通常与POSIX信号量结合使用,以实现进程之间的同步。共享内存是IPC(进程间通信)机制中最快的方法之一,因为它允许进程直接访问同一块内存,而无需进行任何数据复制。
以下是关于POSIX共享内存对象的一些主要特点和使用方式:
使用shm_open
函数创建新的共享内存对象或打开现有的对象。这个函数的行为与open
系统调用类似。
int shm_open(const char *name, int oflag, mode_t mode);
可以使用ftruncate
函数设置共享内存对象的大小。
int ftruncate(int fd, off_t length);
使用mmap
函数将共享内存对象映射到调用进程的地址空间。
void *mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off);
可以使用munmap
函数来解除共享内存对象的映射。
int munmap(void *addr, size_t len);
删除共享内存对象时,它不再可以被新的进程打开,但已经打开并映射到其地址空间的进程仍然可以访问它。使用shm_unlink
函数来删除一个共享内存对象。
int shm_unlink(const char *name);
示例
两个进程可以使用上述机制来实现一个简单的共享计数器。
注意
shm_open()
是一个POSIX函数,用于在POSIX共享内存对象之间创建或打开一个命名连接。这个函数使得多个进程可以共享一块内存,允许它们之间进行高效的数据交换或通信。
共享内存通常比其他进程间通信(IPC)机制(如消息队列或管道)提供更高的性能,因为数据不需要在进程之间复制,而是直接在共享内存中进行读写。
以下是 shm_open()
函数的基本参数和它们的描述:
名称 (name
):
/
)开始的一个字符串。多个进程可以使用相同的名称来引用相同的共享内存对象。标志 (oflag
):
open()
系统调用中使用的标志相同,如 O_RDWR
(读写模式)或 O_CREAT
(如果共享内存对象不存在则创建)。模式 (mode
):
S_IRUSR | S_IWUSR
允许文件的所有者读写访问。函数的基本原型如下:
int shm_open(const char *name, int oflag, mode_t mode);
返回值:
shm_open()
返回一个文件描述符,用于进一步的操作,例如使用 ftruncate()
设置共享内存大小或使用 mmap()
将其映射到进程的地址空间。-1
,并设置全局变量 errno
以指示错误原因。一些常见的使用场景和注意事项:
大小设置: 使用 shm_open()
打开或创建的共享内存对象的初始大小为0。需要使用 ftruncate()
来设置适当的大小。
映射: 为了在进程的地址空间中访问共享内存,需要使用 mmap()
函数将其映射到进程的地址空间。
关闭和删除: 与共享内存相关的两个操作是 shm_unlink()
(从系统中删除共享内存对象的名称)和 close()
(关闭共享内存的文件描述符)。删除共享内存对象的名称并不意味着立即释放其资源;只有在没有进程映射这块内存时,系统才会真正释放其相关资源。
总的来说,shm_open()
提供了一个高效、灵活的进程间通信机制,适用于需要大量数据交换或低延迟通信的应用。
shm_unlink()
是一个POSIX函数,用于删除一个命名的共享内存对象。当一个共享内存对象不再需要被多个进程访问时,通常使用此函数来删除其名称,从而释放相关的系统资源。
以下是 shm_unlink()
的基本参数和描述:
name
):
shm_open()
创建或打开该对象时使用的名称相同的字符串。函数的基本原型如下:
int shm_unlink(const char *name);
返回值:
shm_unlink()
返回 0
。-1
,并设置全局变量 errno
以指示错误原因。一些常见的使用场景和注意事项:
延迟删除:
shm_unlink()
删除了共享内存对象的名称,只要还有进程映射或打开了这个对象,它在物理上仍然存在。只有在最后一个引用被关闭或取消映射后,系统才会真正释放其相关资源。避免资源泄漏:
并发控制:
总的来说,shm_unlink()
是共享内存生命周期管理的一个重要部分,它使您可以在不再需要共享内存对象时释放相关资源。在设计使用共享内存的应用程序时,正确地使用它可以避免资源泄漏和系统资源的滥用。
下面是一个示例,展示了如何使用shm_open()
, shm_unlink()
, mmap()
, munmap()
, ftruncate()
等函数创建、使用和删除一个共享内存区域。在这个例子中,我们将创建两个进程:一个生产者和一个消费者,生产者向共享内存写入数据,消费者从共享内存读取数据。
#include
#include
#include
#include
#include
#include
#include
#include
#define SHM_NAME "/my_shared_memory"
#define SHM_SIZE 4096
int main() {
int shm_fd;
char *shared_memory;
// Create or open a shared memory segment
shm_fd = shm_open(SHM_NAME, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
if (shm_fd == -1) {
perror("shm_open");
return 1;
}
// Set the size of the shared memory segment
if (ftruncate(shm_fd, SHM_SIZE) == -1) {
perror("ftruncate");
return 1;
}
// Map the shared memory segment in the address space of the process
shared_memory = mmap(0, SHM_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
if (shared_memory == MAP_FAILED) {
perror("mmap");
return 1;
}
pid_t pid = fork();
if (pid == 0) { // Child - Consumer
printf("Consumer reading...\n");
while (strncmp(shared_memory, "exit", 4) != 0)
{
printf("Consumed: %s\n", shared_memory);
sleep(2);
}
}
else if (pid > 0) { // Parent - Producer
char *messages[] = {
"Hello from producer",
"This is shared memory",
"exit"};
for (int i = 0; i < 3; i++) {
strncpy(shared_memory, messages[i], SHM_SIZE - 1);
printf("Produced: %s\n", messages[i]);
sleep(1);
}
// Wait for child to finish
wait(NULL);
// Remove the shared memory segment
if (shm_unlink(SHM_NAME) == -1) {
perror("shm_unlink");
return 1;
}
}
else {
perror("fork");
return 1;
}
// Unmap the shared memory
if (munmap(shared_memory, SHM_SIZE) == -1) {
perror("munmap");
return 1;
}
return 0;
}
这个例子包括以下步骤:
shm_open()
创建或打开一个命名的共享内存段。ftruncate()
设置共享内存段的大小。mmap()
将共享内存段映射到进程的地址空间。munmap()
取消映射。shm_unlink()
删除共享内存段。