共享内存--函数

本文详细介绍了共享内存的概念及其在进程间通信中的应用。包括共享内存的基本原理、如何通过shmget、shmat、shmdt和shmctl等函数进行创建、连接、分离及控制,以及权限标志的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

共享内存允许两个不相关的进程访问同一个逻辑内存。共享内存是在两个正在运行的进程之间传递数据的一种非常有效的方式。大多数的共享内存的具体实现,都把由不同进程之间共享的内存安排为同一段物理内存。

共享内存是由IPC为进程创建的一个特殊的地址范围,它将出现在该进程的地址空间中。其他进程可以将同一段共享内存连接到它们自己的地址空间中。所有进程都可以访问共享内存中的地址,就好像它们是malloc分配的一样。如果一个进程向共享内存写入了数据,所做的改动将立刻被可以访问同一段共享内存的任何其他进程看到。

共享内存本身并未提供任何同步机制。在第一个进程结束对共享内存的写操作之前,并无自动的机制可以阻止第二个进程开始对它进行读取。对共享内存访问的同步控制必须由程序员来负责。

头文件: #include <sys/shm.h>

1、shmget函数

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

与信号量一样,程序需要提供一个参数key,它有效的为共享内存段命名,shmget函数返回一个共享内存标识符,该标识符将用于后续的共享内存函数。

第二个参数size以字节为单位指定需要共享的内存容量。

第三个参数shmflg包含九个比特的权限标志。

权限标志对共享内存非常有用,因为它们允许一个进程创建的共享内存可以被共享内存的创建者所拥有的进程写入,同时其他用户创建的进程只能读取该共享内存。我们可以利用这个功能来提供一种有效的对数据进行只读访问的方法,通过将数据放入共享内存并设置它的权限,就可以避免数据被其它用户修改。

如果共享内存创建成功,shmget返回一个非负整数,即共享内存标识符;如果失败,就返回-1.

 

2、shmat函数

第一次创建共享内存段时,它不能被任何进程访问。要想启用对该共享内存的访问,必须将其连接到一个进程的地址空间中。

这项工作由shmat函数来完成。

void *shmat(int   shm_id,  const void *shm_addr,int   shmflg);

第一个参数shm_id是由shmget返回的共享内存标识符。

第二个参数shm_addr指定的是共享内存连接到当前进程中的地址位置。它通常是一个空指针,表示让系统来选择共享内存出现的地址。

第三个参数shmflg是一组位标志。它的两个可能值是SHM_RND(这个标志与shm_addr联合使用,用来控制共享内存连接的地址)和SHM_RDONLY(它使得连接的内存只读)。我们很少需要控制共享内存连接的地址,通常让系统为你选择一个地址,否则就会使应用程序对硬件的依赖性过高。

如果shmat调用成功,它返回一个指向共享内存第一个字节的指针;如果失败,它就返回-1.

 

3、shmdt函数

shmdt函数的作用是将共享内存从当前进程中分离。它的参数是shmat返回的地址指针。成功时它返回0,失败时返回-1.注意,将共享内存分离并未删除它,只是使得该内存对当前进程不再可用。

 

4、shmctl函数

int shmctl(int shm_id, int command,struct  shmid_ds   *buf);

 

struct  shmid_ds{

uid_t   shm_perm.uid;

uid_t  shm_perm.gid;

mode_t  shm_perm.mode;

}

 

第一个参数shm_id是shmget返回的共享内存标识符。

第二个参数command是要采取的动作,它可以取三个值。

 

IPC_STAT        把shmid_ds结构中的数据设置为共享内存的当前关联值

IPC_SET          如果进程有足够的权限,就把共享内存的当前关联值设置为shmid_ds结构中的值

IPC_RMID        删除共享内存段

 

第三个参数buf是一个指针,它指向包含共享内存模式和访问权限的结构。

成功返回0,失败返回-1。 

在 MFC 中,使用共享内存(Shared Memory)和 CMutex 构造函数进行跨线程或跨进程同步时,需要特别注意互斥对象的构造参数以及共享内存的管理方式。 ### 共享内存与 CMutex 的结合使用 MFC 本身并未直接提供共享内存的封装类,但可以通过 Windows API 如 `CreateFileMapping` 和 `MapViewOfFile` 实现共享内存机制。与此同时,CMutex 被用来保护共享内存区域,以确保多个线程或进程不会同时访问共享资源,从而避免数据竞争问题 [^2]。 #### CMutex 构造函数参数说明 CMutex 类的构造函数原型如下: ```cpp CMutex(BOOL bInitiallyOwn = FALSE, LPCTSTR lpszName = NULL, LPSECURITY_ATTRIBUTES lpsaAttribute = NULL); ``` - `bInitiallyOwn`:指定互斥体初始状态是否被当前线程拥有。若设置为 TRUE,则当前线程立即获得该互斥体。 - `lpszName`:互斥体名称,用于跨进程标识同一个互斥对象。如果希望不同进程访问同一互斥体,则必须提供相同的名称 [^3]。 - `lpsaAttribute`:指向安全属性结构的指针,通常设为 NULL,表示使用默认安全描述符 [^2]。 #### 使用示例 以下是一个使用 CMutex 保护共享内存的典型场景: ```cpp // 创建共享内存 HANDLE hFileMap = CreateFileMapping( INVALID_HANDLE_VALUE, // 使用系统分页文件 NULL, // 默认安全属性 PAGE_READWRITE, // 可读写 0, // 高位文件大小 sizeof(SHARED_DATA), // 低位文件大小 _T("MySharedMemory")); // 共享内存名称 if (hFileMap == NULL) { AfxMessageBox(_T("CreateFileMapping failed.")); return; } // 映射到当前进程地址空间 SHARED_DATA* pData = (SHARED_DATA*)MapViewOfFile( hFileMap, // 已创建的文件映射对象 FILE_MAP_ALL_ACCESS, // 可读可写 0, 0, sizeof(SHARED_DATA)); if (pData == NULL) { AfxMessageBox(_T("MapViewOfFile failed.")); CloseHandle(hFileMap); return; } // 创建或打开命名互斥体 CMutex mutex(FALSE, _T("MySharedMemoryMutex")); // 在访问共享内存前加锁 mutex.Lock(); // 操作共享内存 pData->value = 42; // 完成操作后解锁 mutex.Unlock(); // 清理资源 UnmapViewOfFile(pData); CloseHandle(hFileMap); ``` 上述代码中,CMutex 被构造为一个命名互斥体,以便多个进程可以访问它。通过调用 `Lock()` 和 `Unlock()` 方法来保护对共享内存的访问。 ### 注意事项 - 若多个进程需访问同一块共享内存,它们都必须使用相同的名称调用 `CreateFileMapping` 和 `CMutex` 构造函数- 应确保在程序结束时正确释放互斥体并卸载共享内存映射,以防止资源泄漏。 - 使用 CMutex 时,建议始终检查其返回值,以确保互斥体成功创建或打开 [^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值