共享内存:
共享内存是最快的IPC形式。一旦这样的内存映射到共享它的进程的地址空间,这些进程间数据传递不再涉及到内核,换句话说是进程不再通过执行进入内核的系统调用来传递彼此的数据。
共享内存示意图:
共享内存数据结构:
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 */
...
};
共享内存函数:
shmget函数:
功能:用来创建或打开共享内存
原型:
int shmget(key_t key, size_t size, int shmflg);
参数: key:这个共享内存段名字
size:共享内存大小
shmflg:创建时用 IPC_CREAT|0644 打开直接是0
返回值:成功返回一个非负证书,即该共享内存段的标识码;失败返回-1.
shmat函数:
功能:将共享内存段连接到进程地址空间
原型:
void *shmat(int shmid, const void *shmaddr, int shmflg);
参数: shmid:共享内存标识
shmaddr:指定连接地址
shmflg:SHM_RND或SHM_RDONLY
返回值: 成功返回一个指针,指向共享内存第一个节;失败返回-1.
说明:
shmaddr 为 NULL时, 核心自动选择一个地址。
shmaddr不为BNULL, 且shmflg无SHM_RND标记,则以shmaddr为连接地址。
shmaddr不为NULL且shmflg设置了SHM_RND标记,则连接的地址会自动向下调整为SHMLBA的整数倍,公式:shmaddr - (shmaddr % SHMLBA)
shmflg = SHM_RDONLY,表示连接操作用来只读共享内存
shmdt函数:
功能:将共享内存与当前进程脱离
int shmdt(const void *shmaddr);
参数: shmaddr:由shmad所返回的指针
返回值: 成功返回0,失败返回-1.
注意:将共享内存与当前进程脱离不等于删除共享内存段
shmctl函数:
功能:用于控制共享内存原型:
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
参数: shmid: 由shmget返回的共享内存标识码
cmd:将要采取的动作(由三个可取的值)
buf:指向一个保存着共享内存的模式状态和访问权限的数据结构
返回值: 成功返回0,失败返回-1.
注意:cmd命令如下所示:
测试用例:写一个read.c 和 write.c 两个进程,开辟一块共享内存, A进程是write.c 向共享内存中写数据,B进程是read.c从共享内存中取数据。
create.c程序:创建一个共享内存
#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int main( void )
{
int num = 10;
int id = shmget(ftok(".", 'a'), sizeof(int), IPC_CREAT|0666);
if ( id == -1 ) perror("shmget"),exit(1);
printf("create ok\n");
}
A进程, write.c向共享内存写入内容
#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int main( void )
{
int id = shmget(ftok(".", 'a'), sizeof(int), 0);
if ( id == -1 ) perror("shmget"),exit(1);
int *p = (int*)shmat(id, NULL, 0);
int i = 1;
for ( ; ; ) {
*p = i++;
sleep(1);
}
}
B进程,从共享内存中取数据。
#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int main( void )
{
int id = shmget(ftok(".", 'a'), sizeof(int), 0);
if ( id == -1 ) perror("shmget"),exit(1);
int *p = (int*)shmat(id, NULL, 0);
while ( 1 ){
printf("%d\n", *p);
}
}
运行结果如下:
结果分析:
在write.c中,一秒写入一个值,而在read.c中,一直在读取,所以拿到的数据就会一段时间是一个值,如何解决共享内存同步的问题,还需继续学习探索,可以通过信号量集,PV操作来解决此类问题。