共享内存更像是客户端从服务端申请内存(这里的服务端是内核,客户端是用户进程或线程),这块内存通过特殊标识来进行区分,通过内核的api,给定内存的特殊标识,内核返回给进程所需的内存。则可以通过对其对写实现进行通讯(因为其他进程只要知道这个特殊标识,就可以得到这块内存的读写权限)。
因为设计到多进程对同一内存的读写,所以涉及到进程同步,需要加入信号量等其他东西。当然内存共享效率高。
用法:
#include <sys/ipc.h>
#include <sys/shm.h>
1.int shmget(key_t key, size_t size, int shmflg);
得到一个共享内存标识符或创建一个共享内存对象并返回共享内存标识符
key: 标识,相同的key获得相同地址的内存。
size:内存块大小
shmflg:属性
IPC_CREAT: 创建新的共享内存,如果没使用这个flag,函数会去找关联这个key的共享内存并检查用户是否有访问该共享内存的权限。
IP_EXCL:和IPC_CREAT联合使用,确保失败,如果共享内存存在。如果创建成功返回shmid,创建失败,返回-1。
2,void *shmat(int shmid, const void *shmaddr, int shmflg);
把shmid关联的共享内存挂载在进程的地址空间里。
第一个是参数是 shmid 是shmget 返回的标识符,
第二个参数 三种情况 1.如果shmaddr 是NULL,系统将自动选择一个合适的地址! 2.如果
shmaddr 不是NULL 并且没有指定SHM_RND则此段连接到addr所指定的地址上。 3.如果shmaddr
非0 并且指定了SHM_RND 则此段连接到shmaddr -(shmaddr mod SHMLAB)所表示的地址上。这里
解释一下SHM_RND命令,它的意思是取整,而SHMLAB的意思是低边界地址的倍数,它总是2的乘方,该
算式是将地址向下取最近一个SHMLAB的倍数。 除非只计划在一种硬件上运行应用程序(在现在是不太可
能的),否则不用指定共享段所连接到的地址。所以一般指定shmaddr为0,以便由内核选择地址。
第三个参数如果在flag中指定了SHM_RDONLY位,则以只读方式连接此段,否则以读写的方式连接此
段。 shmat返回值是该段所连接的实际地址,如果出错返回 -1。
3.int shmdt(const void *shmaddr);
将挂载在调用进程内的共享内存分离出来。
shmaddr:共享内存挂载的地址。
4.int shmctl(int shmid, int cmd, struct shmid_ds *buf);
控制共享内存,通过cmd。
shmid 共享内存标识ID;
cmd IPC_STAT 得到共享内存的状态
IPC_SET 改变共享内存的状态
IPC_RMID 删除共享内存(当最后一个进程将共享内存分离出去之后,共享内存才被销毁)
buf 是一个结构体指针。IPC_STAT的时候,取得的状态放在这个结构体中。如果要改变共享内存的状态,用这个结构体指定;
struct shmid_ds {
struct ipc_perm shm_perm; /* Ownership and permissions */
size_t shm_segsz; /* Size of segment (bytes) */
time_t shm_atime; /* Last attach time */
time_t shm_dtime; /* Last detach time */
time_t shm_ctime; /* Last change time */
pid_t shm_cpid; /* PID of creator */
pid_t shm_lpid; /* PID of last shmat(2)/shmdt(2) */
shmatt_t shm_nattch; /* No. of current attaches */
...
};