Linux——进程间通信(共享内存shm)笔记
Linux——进程间通信(共享内存shm)笔记
文章目录前言
一、共享内存的通信原理
二、共享内存函数1.共享内存实现步骤
2.函数的说明1.shmget( )函数
2.shmat( )函数
3.shmdt( )函数
三、代码示例:
执行结果显示
总结
前言
??共享内存是一种最为高效的进程间通信方式。因为进程可以直接读写内存,不需要任何数据的拷贝。为了在多个进程间交换信息,内核专门留出了一块内存区。这段内存区可以由需要访问的进程将其映射到自己的私有地址空间。因此,进程就可以直接读写这一内存区而不需要进行数据的拷贝,从而大大提高了效率。
??共享内存并未提供同步机制,也就是说,在第一个进程结束对共享内存的写操作之前,并无自动机制可以阻止第二个进程开始对它进行读取。所以我们通常需要用其他的机制来同步对共享内存的访问,如互斥锁和信号量等。
一、共享内存的通信原理
??在Linux中,每个进程都有属于自己的进程控制块(PCB)和地址空间(Addr Space),并且都有一个与之对应的页表,负责将进程的虚拟地址与物理地址进行映射,通过内存管理单元(MMU)进行管理。两个不同的虚拟地址通过页表映射到物理空间的同一区域,它们所指向的这块区域即共享内存。
??共享内存的通信原理示意图:
二、共享内存函数
[var1]
创建共享内存 ?&emsp:shmget( )
映射共享内存?&emsp: shmat( )
撤销映射?&emsp: shmdt( )
[var1]
1.shmget( )函数
头文件:
#include
#include
#include
函数原型:
int shmget(key_t key,int size,int shmflg)
函数参数:
【Key】:共享内存的键值,多个进程可以通过它,来访问同一个共享内存;其中特殊的值IPC_PRIVATE,用于创建当前进程的私有共享内存, 多用于父子进程间。
【 size】:共享内存区大小 。
【Shmflg】:同 open 函数的权限位,也可以用八进制表示法
返回值:
??成功:共享内存段标识符
??出错:-1
2.shmat( )函数
3.shmdt( )函数
三、代码示例:
共享内存并未提供同步机制,所以需要额外的实现不同进程之间的同步,为了简单,本例中用标志字符串来实现简单的父子进程间的同步。
/* shmem.c */
#include
#include
#include
#include
#include
#include
#define BUFFER_SIZE 2048
int main()
{
pid_t pid;
int shmid;
char *shm_addr;
char flag[] = "WROTE";
char *buff;
/* 创建共享内存 */
if ((shmid = shmget(IPC_PRIVATE, BUFFER_SIZE, 0666)) < 0)
{
perror("shmget");
exit(1);
}
else
{
printf("Create shared-memory: %d\n",shmid);
}
/* 显示共享内存情况 */
system("ipcs -m");
pid = fork();
if (pid == -1)
{
perror("fork");
exit(1);
}
else if (pid == 0) /* 子进程处理 */
{
/*映射共享内存*/
if ((shm_addr = shmat(shmid, 0, 0)) == (void*)-1)
{
perror("Child: shmat");
exit(1);
}
else
{
printf("Child: Attach shared-memory: %p\n", shm_addr);
}
system("ipcs -m");
/* 通过检查在共享内存的头部是否标志字符串"WROTE"来确认父进程已经向共享内存写入有效数据 */
while (strncmp(shm_addr, flag, strlen(flag)))
{
printf("Child: Wait for enable data...\n");
sleep(5);
}
/* 获取共享内存的有效数据并显示 */
strcpy(buff, shm_addr + strlen(flag));
printf("Child: Shared-memory :%s\n", buff);
/* 解除共享内存映射 */
if ((shmdt(shm_addr)) < 0)
{
perror("shmdt");
exit(1);
}
else
{
printf("Child: Deattach shared-memory\n");
}
system("ipcs -m");
if (shmctl(shmid, IPC_RMID, NULL) == -1)
{
perror("Child: shmctl(IPC_RMID)\n");
exit(1);
}
else
{
printf("Delete shared-memory\n");
}
system("ipcs -m");
}
else /* 父进程处理 */
{
/*映射共享内存*/
if ((shm_addr = shmat(shmid, 0, 0)) == (void*)-1)
{
perror("Parent: shmat");
exit(1);
}
else
{
printf("Parent: Attach shared-memory: %p\n", shm_addr);
}
sleep(1);
printf("\nInput some string:\n");
fgets(buff, BUFFER_SIZE, stdin);
strncpy(shm_addr + strlen(flag), buff, strlen(buff));
strncpy(shm_addr, flag, strlen(flag));
/* 解除共享内存映射 */
if ((shmdt(shm_addr)) < 0)
{
perror("Parent: shmdt");
exit(1);
}
else
{
printf("Parent: Deattach shared-memory\n");
}
system("ipcs -m");
waitpid(pid, NULL, 0);
printf("Finished\n");
}
exit(0);
}
执行结果显示
总结
本方法是通过访问物理内存来实现的进程间通信。
通过上述三个函数的配合可以实现进程间通信。但是,其本身是不具备同步机制的,需要额外的提供同步机制。
Linux——进程间通信(共享内存shm)笔记相关教程