IPC通信_共享内存
共享内存允许两个或多个进程共享一个给定的存储区,就是多个进程将同一块物理内存映射到自己的虚拟地址上。因为不需要在客户进程和服务进程之间拷贝,所以是最快的一种IPC。
函数1
#include <sys/shm.h> int shmget(key_t key, size_t size, int flag);
该函数转换键值获取共享内存ID, key键值的获取还是通过ftok函数。
返回值:成功返回共享内存ID, 失败返回-1
参数key:键值(key)
参数size:请求的共享内存的长度,单位字节,如果引用一个现存在的段,将size置为0
参数flag:设置的权限,可参考消息队列。
函数2
#include <sys/shm.h> int shmctl(int shmid, int cmd, struct shmid_ds *buf);
该函数对共享内存执行多种操作。
返回值:成功返回0,失败返回-1
参数shmid:共享内存ID
参数cmd:见下表
cmd参数 |
释意 |
IPC_STAT |
参考消息队列 |
IPC_SET |
参考消息队列 |
IPC_RMID |
参考消息队列 |
SHM_LOCK |
在内存中对共享存储段加锁,此命令只能由超级用户执行 |
SHM_UNLOCK |
解锁共享存储段。此命令只能由超级用户执行 |
函数3
#include <sys/shm.h> void *shmat(int shmid, const void *addr, int flag);
调用该函数将共享内存段连接到该进程的虚拟地址空间中
返回值: 成功返回共享内存段的指针,失败返回-1
参数shmid: 共享内存的ID
参数addr: 推荐为0,此时申请的共享内存连接到内核选择的一个可用地址上。
如果非0,并且没有指定SHM_RND,则连接到addr所指定地址
如果非0,且指定了SHM_RND,则连接到(addr-(addr mod SHMLBA))所表示的地址
参数flag:如果置位 SHM_RDONLY,则以只读方式连接,否则以读写方式连接此段
函数4
#include <sys/shm.h> void *shmdt( const void *addr);
当对共享内存段的操作结束时,调用该函数与共享内存段分离。注意,这并不是从系统中删除其表示符以及相关数据结构,标识符依旧存在,直至某个进程带IPC_RMID命令的调用shmctl特地的删除为止。
返回值 :成功返回0,失败返回-1
参数addr:之前调用shmat的返回值
举例:
两个进程通过共享内存实现一个读,一个写,利用信号量实现同步
shmwrite.cpp
#include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <sys/shm.h> #include <sys/sem.h> #include <string.h> #include <iostream> #define BUFSIZE 128 union semun { int val; struct semid_ds *buf; unsigned short *arry; }; int set_semvalue(int sem_id, int count) {//用于初始化信号量,在使用信号量前必须这样做 union semun sem_union; sem_union.val = count; if(semctl(sem_id, 0, SETVAL, sem_union) == -1) { printf("set_semvalue failed\n"); return -1; } return 0; } void del_semvalue(int sem_id) {//删除信号量 union semun sem_union; if(semctl(sem_id, 0, IPC_RMID, sem_union) == -1) { printf("del_semvalue failed\n"); } } int semaphore_p(int sem_id) {//对信号量做减1操作,即等待P(sv) struct sembuf sem_b; sem_b.sem_num = 0; sem_b.sem_op = -1;//P() sem_b.sem_flg = SEM_UNDO; if(semop(sem_id, &sem_b, 1) == -1) { printf("semaphore_p failed\n"); return -1; } return 0; } int semaphore_v(int sem_id) {//这是一个释放操作,它使信号量变为可用,即发送信号V(sv) struct sembuf sem_b; sem_b.sem_num = 0; sem_b.sem_op = 1;//V() sem_b.sem_flg = SEM_UNDO; if(semop(sem_id, &sem_b, 1) == -1) { printf("semaphore_v failed\n"); return -1; } return 0; } int main(void) { //创建信号量 int sem_id = semget((key_t)4321, 1, 0666 | IPC_CREAT); set_semvalue(sem_id, 0); //创建共享内存 int shmid = shmget((key_t)1234, BUFSIZE, 0666|IPC_CREAT); if(shmid == -1) { printf("shmget failed\n"); return -1; } //将共享内存连接到当前进程的地址空间 char* buf = (char*)shmat(shmid, (void*)0, 0); if(buf == (void*)-1) { printf("shmget failed\n"); return -1; } printf("Memory attached at %p\n", buf); std::string str; while(std::cin>>str)//向共享内存中写数据 { //输入了end,退出循环(程序) if(str == "end") break; memset(buf,0,BUFSIZE); strncpy(buf, str.c_str(), BUFSIZE); semaphore_v(sem_id);//信号量V操作 } //把共享内存从当前进程中分离 if(shmdt(buf) == -1) { printf("shmdt failed\n"); return -1; } shmctl(shmid,IPC_RMID,NULL);//删除共享内存 del_semvalue(sem_id); //删除信号量 return 0; }
shmread.cpp
#include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <sys/shm.h> #include <sys/sem.h> #include <string.h> #include <iostream> #define BUFSIZE 128 union semun { int val; struct semid_ds *buf; unsigned short *arry; }; int set_semvalue(int sem_id, int count) {//用于初始化信号量,在使用信号量前必须这样做 union semun sem_union; sem_union.val = count; if(semctl(sem_id, 0, SETVAL, sem_union) == -1) { printf("set_semvalue failed\n"); return -1; } return 0; } void del_semvalue(int sem_id) {//删除信号量 union semun sem_union; if(semctl(sem_id, 0, IPC_RMID, sem_union) == -1) { printf("del_semvalue failed\n"); } } int semaphore_p(int sem_id) {//对信号量做减1操作,即等待P(sv) struct sembuf sem_b; sem_b.sem_num = 0; sem_b.sem_op = -1;//P() sem_b.sem_flg = SEM_UNDO; if(semop(sem_id, &sem_b, 1) == -1) { printf("semaphore_p failed\n"); return -1; } return 0; } int semaphore_v(int sem_id) {//这是一个释放操作,它使信号量变为可用,即发送信号V(sv) struct sembuf sem_b; sem_b.sem_num = 0; sem_b.sem_op = 1;//V() sem_b.sem_flg = SEM_UNDO; if(semop(sem_id, &sem_b, 1) == -1) { printf("semaphore_v failed\n"); return -1; } return 0; } int main(void) { //获取信号量 int sem_id = semget((key_t)4321, 1, 0666 | IPC_CREAT); //获取共享内存 int shmid = shmget((key_t)1234, 0, 0666|IPC_CREAT); if(shmid == -1) { printf("shmget failed\n"); return -1; } //将共享内存连接到当前进程的地址空间 char* buf = (char*)shmat(shmid, (void*)0, 0); if(buf == (void*)-1) { printf("shmget failed\n"); return -1; } printf("Memory attached at %p\n", buf); while(1) { semaphore_p(sem_id);//信号量P操作 printf("read buf:%s\n",buf); } //把共享内存从当前进程中分离 if(shmdt(buf) == -1) { printf("shmdt failed\n"); return -1; } del_semvalue(sem_id); //删除信号量 return 0; }