目录
1 概念
2 操作流程
fork(获取key值)
shmget(申请对象)
shmat(内存映射)
读写共享内存:类似堆区内存的直接读写
shmdt(解除映射)
shmctl(删除对象)
范例:
1 概念
共享内存是进程间通信中最简单最高效的方式之一。共享内存允许两个或更多进程访问同一块内存,就如同 malloc() 函数向不同进程返回了指向同一个物理内存区域的指针。当一个进程改变了这块地址中的内容的时候,其它进程都会察觉到这个更改。
2 操作流程
1 获取K值 ftok
2 申请对象 shmget
3 内存映射 shmat
4 读写共享内存
5 解除映射 shmdt
6 删除对象 shmctl
fork(获取key值)
key_t ftok(const char *pathname, int proj_id);
功能:
通过该函数可以将pathname指定的路径用来以proj_id生成唯一的临时键值。
参数:pathname 路径 ,任意路径,只要不会被删除即可。但是读写端路径指向必须一致proj_id 代号,整形的数据,一般用ASCII码的单字符表示
返回值:
成功 返回唯一键值
失败 -1;
shmget(申请对象)
int shmget(key_t key, size_t size, int shmflg);
功能:
创建共享内存
参数:
key:键值
size:共享内存大小
shmflg:
IPC_CREAT 创建 (低9个bits表示用户,同组用户,其他人的权限)
IPC_EXCL 检测是否存在
返回值:
成功返回共享内存ID
失败返回-1
shmat(内存映射)
void *shmat(int shmid, const void *shmaddr, int shmflg);
功能:
将指定shmid对应的共享内存映射到本地内存。
参数:shmid 要映射的共享内存id
shmaddr 本地可用的地址,如果不确定则用NULL,表示由系统自动分配。
shmflg :操作权限
SHM_RDONLY,只读
!SHM_RDONLY 读写
返回值:成功 返回映射的地址,一般等于shmaddr
失败 (void*) -1
读写共享内存:类似堆区内存的直接读写
shmdt(解除映射)
int shmdt(const void *shmaddr);
功能:
将本地内存与共享内存断开映射关系。
参数:shmaddr 要断开的映射地址。
返回值:成功 0
失败 -1;
shmctl(删除对象)
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
功能:
修改共享内存属性,也可以删除指定的共享内存对象。
参数:shmid 要删除的共享内存对象
cmd
IPC_STAT 获得信息
IPC_SET 设置权限
IPC_RMID 删除
buff
NULL 表示只删除对象。
返回值:成功 0
范例:
编写两个进程任务利用共享内存通信,一个负责从终端接写入共享内存中,另一个负责打印共享内存数据,直到输入quit两个进程任务结束
进程1发送
#include <stdio.h> #include <unistd.h> #include <pthread.h> #include <string.h> #include <stdlib.h> #include <time.h> #include <semaphore.h> #include <sys/wait.h> #include <sys/stat.h> #include <fcntl.h> #include <errno.h> #include <signal.h> #include <sys/ipc.h> #include <sys/shm.h> int main(int argc, char const *argv[]) { key_t key; printf("\33[35m\33[1mmess_t\33[0m\33[36m\33[1m开始配对...\33[0m\n"); key = ftok(".",258);//获取k值-----1 if(-1 == key) { perror("fail to ftok"); return 0; } printf("key: 0X%x\n",key); int shm_id = shmget(key,4096,IPC_CREAT | 0666);//申请对象-----2 if(-1 == shm_id) { perror("fail to shmget"); return 0; } printf("shmID: %d\n",shm_id); void *pmem = shmat(shm_id,NULL,!SHM_RDONLY);//内存映射-----3 if((void *)-1 == pmem) { perror("fail to shmat"); return 0; } pid_t R_pid = *(pid_t *)pmem; printf("R_pid = %d\n",R_pid); char tmpbuf[4096] = {0}; printf("\33[32m\33[1mmess_t配对成功!\33[0m\n"); while (1)//写共享内存-----4 { printf("\33[35m\33[1mmess_t发送:\33[0m"); fgets(tmpbuf,sizeof(tmpbuf),stdin); if(!strcmp("quit\n",tmpbuf))break; memcpy(pmem,tmpbuf,sizeof(tmpbuf)); kill(R_pid,12); } shmdt(pmem);//解除映射-----5 shmctl(shm_id,IPC_RMID,NULL);//删除对象-----6 printf("BAIBAI!!!\n"); kill(R_pid,10); return 0; }
进程2接收
#include <stdio.h> #include <unistd.h> #include <pthread.h> #include <string.h> #include <stdlib.h> #include <time.h> #include <semaphore.h> #include <sys/wait.h> #include <sys/stat.h> #include <fcntl.h> #include <errno.h> #include <signal.h> #include <sys/ipc.h> #include <sys/shm.h> int stat_0_1 = 1; void handler(int arg) { alarm(0); } void end(int arg) { stat_0_1 = 0; } int main(int argc, char const *argv[]) { signal(SIGALRM, SIG_DFL); // 缺省默认 signal(12, handler); // 缺省默认 signal(10, end); key_t key; printf("\33[31m\33[1mmess_r\33[0m\33[36m\33[1m开始配对...\33[0m\n"); key = ftok(".", 258); // 获取k值-----1 if (-1 == key) { perror("fail to ftok"); return 0; } printf("key: 0X%x\n", key); int shm_id = shmget(key, 4096, IPC_CREAT | 0666); // 申请对象-----2 if (-1 == shm_id) { perror("fail to shmget"); return 0; } printf("shmID: %d\n", shm_id); void *pmem = shmat(shm_id, NULL, !SHM_RDONLY); // 内存映射-----3 if ((void *)-1 == pmem) { perror("fail to shmat"); return 0; } pid_t *pid = pmem; *pid = getpid(); char tmpbuf[4096] = {0}; printf("\33[32m\33[1mmess_r配对成功!\33[0m\n"); while (1) { if (stat_0_1) { pause(); // 挂起,等待信号 printf("\33[31m\33[1mmess_r收到:\33[0m\33[1m%s", (char *)pmem); } else { break; } } shmdt(pmem); // 解除映射-----5 shmctl(shm_id, IPC_RMID, NULL); // 删除对象-----6 printf("BAIBAI!!!\n"); return 0; }
运行结果