0%

C++ Linux IPC进程通信-共享内存

原文链接:C++ Linux IPC进程通信-共享内存

共享内存<sys/shm.h>

库函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// 创建共享内存
int shmget(key_t key, size_t size, int shmflg);
return 共享内存的ID(成功) -1(错误)
key为一个标记内存的关键字,可用自己指定,也可以用ftok函数转文件名为key,
shmflg标志包括IPC_CREAT(创建)|IPC_EXCL(存在则报错)|SHM_RDONLY(只读)|SHM_RND(附加到指定地址的最接近的可用地址)|SHM_NORESERVE(不预留共享内存资源)

!!:注意IPC命名对象需要指定该对象的文件权限如IPC_CREAT|0666

// 分配空间并连接
void *shmat(int shm_id, const void *shm_addr, int shmflg);
return 分配空间首地址 或 -1
shm_id为返回的id shm_addr为nullptr自动分配,否则就近分配 shmflg可为SHM_RDONLY(只读)|SHM_NORESERVE(不预留共享内存资源)

// 删除连接(不删除空间)
int shmdt(const void *shmaddr); shmaddr为首地址
return 成功0,出错-1

//控制
int shmctl(int shm_id, int cmd, struct shmid_ds *buf);
return 成功0,出错-1
cmd:IPC_STAT(读出数据到buf),IPC_SET(写入),IPC_RMID(删除共享内存)

该控制命令实际上就是通过更新结构体来控制共享内存配置,如分配大小或其他的
struct shmid_ds {
uid_t shm_perm.uid;
uid_t shm_perm.gid;
mode_t shm_perm.mode;
//其他配置
};

使用memcpy实现数据的移动

实例:使用信号量+共享内存实现变量自增

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#include <iostream>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <fcntl.h>
#include <semaphore.h>
#include <unistd.h>
#include <string.h>
using namespace std;

class Cnt{
public:
int c; //需要共享
string s; //不需要共享
Cnt():c(0),s(""){};
~Cnt(){};
};
template <typename T>
void check(const char* er, const T& a, const T& b) {
if (a == b) {
perror(er);
exit(EXIT_FAILURE);
}
}

void run(Cnt &cnt,sem_t *nsem,void *addr,int size){
for(int i=0;i<3;i++){
sem_wait(nsem);
memcpy(&(cnt.c),addr,size);
cnt.c++;
cout<<cnt.c<<"\n";
memcpy(addr,&(cnt.c),size);
sem_post(nsem);
}
}

int main()
{
Cnt cnt;
int size= sizeof(cnt.c);

sem_t* nsem=sem_open("name_sem",O_CREAT,0666,1);
check(string("sem_open").c_str(),nsem,SEM_FAILED);
int fd=open("./shm",O_CREAT|O_RDWR,0666);
check(string("open").c_str(),fd,-1);
check(string("close").c_str(),close(fd),-1);
key_t k=ftok("./shm",'A');
check(string("ftok").c_str(),k,-1);
int sid=shmget(k,size,IPC_CREAT|0666);
check(string("shmget").c_str(),sid,-1);
void *addr = shmat(sid,nullptr,0);
check(string("shmat").c_str(),addr,(void*)-1);

pid_t cid=fork();
if(cid==-1){
perror("fork");
exit(EXIT_FAILURE);
}else if(cid>0){
run(cnt,nsem,addr,size);
}else{
run(cnt,nsem,addr,size);
}

if(cid>0){
check(string("shmdt").c_str(),shmdt(addr),-1);
check(string("shmctl").c_str(),shmctl(sid,IPC_RMID,nullptr),-1);
check(string("sem_close").c_str(),sem_close(nsem),-1);
check(string("sem_unlink").c_str(),sem_unlink("name_sem"),-1);
}

return 0;
}

特点

优点

优点速度快,大量数据操作下效率高,直接对内存操作.

缺点

需要其他的方法实现同步支持,并且对内存管理和分配有要求