shm进程间通信失败了!!!

网友投稿 570 2022-05-29

稍安勿躁。

先解决问题

如果你是在网上辗转而不得其解,那就来我这儿吧。

之前那篇写的比较急,讲的还是蛮有条理的,就是东西少了点,这篇一次性写完。

那天,我和共享内存、shmid不眠不休只吃一点喝一点奋战了十个小时,只为了把我的项目进度赶在大家前面,却被进程间通信始终无法打通而拦住。解决问题之后,有感而作。

如果放在今天,我会选择采用TCP流协议的方式来进行进程间通信,详情:你会不会分布式系统进程间通信

不过我们现在讲的是shm,好。

以下内容基于在一个进程里至少准备挂两个共享内存,一个用来发,一个用来收

既然用到shm,那自然和key值要打交道。

key值有fotk函数生成,如果对ftok函数不熟,有空可以看一下这篇:ftok

讲的是极好的,不是我写的。

我遇到的第一个问题,是:

不同参数的ftok生成同样的shmid值

shm进程间通信失败了!!!

为什么呢?不知道。

但是我还不算傻,至少知道做个demo把key值打印出来看,全是-1。

ftok的第一个参数得是有效的文件路径。

看了上面那篇文章之后,我将代码进行了修改,接下来就遇到了第二个问题:

同样参数的ftok函数生成了不同的key值

这个就不好找咯,上面那个还能在网上找到点蛛丝马迹,这个要是找到希望能在下面给我留个网址,感激不尽。

这个就不好找咯,上面那个还能在网上找到点蛛丝马迹,这个要是找到希望能在下面给我留个网址,感激不尽。

这个就要分两种情况了(我遇到两种),第一种就是代码的问题,刚开始我写的花里胡哨的,后面老实了,拿到key值之后直接就shm_get, 这下shmid也老实了,不过还是会差,因为key值会偏差一点。

第二种情况,

其实问题也很简单,就是目录的差别。如果你用的是绝对目录那就比较好,但是如果给ftok传参传的是相对目录,而你运行的两个执行文件所在的目录又不同,那么ftok计算key值时从当前进程所在目录出发,自然是会有偏差的。

怎么办?怎么办?

小事情,这里有两个方法:

1、将两个执行文件放在统一目录底下,方法是好方法,不过最好你得会写Makefile

2、使用绝对路径,其实这个方法也能另辟蹊径,什么呢, / ,就是这个斜杠,杠杠的绝对路径

shm共享内存

创建或打开共享内存

#include #include int shmget(key_t key, size_t size, int shmflg);

1

2

3

4

参数不释义,后面有例子

挂载共享内存

#include #include void *shmat(int shmid, const void *shmaddr, int shmflg);

1

2

3

4

分离共享内存

#include int shmdt(const void *shmaddr);

1

2

3

控制共享内存

#include #include int shmctl(int shmid, int cmd, struct shmid_ds *buf);

1

2

3

4

示例

#include "f_shm.h" #include #include #include #include #include #include #include #include #include #include typedef struct shmhead_st { int shmid; // 共享内存ID unsigned int blksize; // 块大小 unsigned int blocks; // 总块数 unsigned int rd_index; // 读索引 unsigned int wr_index; // 写索引 //必须放在共享内存内部才行 sem_t sem_mutex; // 用来互斥用的信号量 sem_t sem_full; // 用来控制共享内存是否满的信号量 sem_t sem_empty; // 用来控制共享内存是否空的信号量 }shmhead_t; F_Shm::F_Shm(key_t key, int blksize, int blocks) { this->open_shm(key, blksize, blocks); } F_Shm::F_Shm() { shmhead = NULL; payload = NULL; open = false; } F_Shm::~F_Shm() { this->close_shm(); } //返回头地址 bool F_Shm::creat_shm(key_t key, int blksize, int blocks) { int shmid = 0; //1. 查看是否已经存在共享内存,如果有则删除旧的 shmid = shmget(key, 0, 0); if (shmid != -1) { shmctl(shmid, IPC_RMID, NULL); // 删除已经存在的共享内存 } //2. 创建共享内存 shmid = shmget(key, sizeof(shmhead_t) + blksize*blocks, 0666 | IPC_CREAT | IPC_EXCL); if(shmid == -1) { ERR_EXIT("shmget"); } printf("Create shmid=%d size=%u \n", shmid, sizeof(shmhead_t) + blksize*blocks); //3.连接共享内存 shmhead = shmat(shmid, (void*)0, 0); //连接共享内存 if(shmhead == (void*)-1) { ERR_EXIT("shmat"); } memset(shmhead, 0, sizeof(shmhead_t) + blksize*blocks); //初始化 //4. 初始化共享内存信息 shmhead_t * pHead = (shmhead_t *)(shmhead); pHead->shmid = shmid; //共享内存shmid pHead->blksize = blksize; //共享信息写入 pHead->blocks = blocks; //写入每块大小 pHead->rd_index = 0; //一开始位置都是第一块 pHead->wr_index = 0; // sem_init(&pHead->sem_mutex, 1, 1); // 第一个1表示可以跨进程共享,第二个1表示初始值 sem_init(&pHead->sem_empty, 1, 0); // 第一个1表示可以跨进程共享,第二个0表示初始值 sem_init(&pHead->sem_full, 1, blocks);// 第一个1表示可以跨进程共享,第二个blocks表示初始值 //5. 填充控制共享内存的信息 payload = (char *)(pHead + 1); //实际负载起始位置 open = true; return true; } void F_Shm::dsy_shm() { shmhead_t *pHead = (shmhead_t *)shmhead; int shmid = pHead->shmid; //删除信号量 sem_destroy (&pHead->sem_full); sem_destroy (&pHead->sem_empty); sem_destroy (&pHead->sem_mutex); shmdt(shmhead); //共享内存脱离 //销毁共享内存 if(shmctl(shmid, IPC_RMID, 0) == -1) //删除共享内存 { printf("Delete shmid=%d \n", shmid); ERR_EXIT("shmctl rm"); } shmhead = NULL; payload = NULL; open = false; } void F_Shm::Destroy(key_t key) { int shmid = 0; //1. 查看是否已经存在共享内存,如果有则删除旧的 shmid = shmget(key, 0, 0); if (shmid != -1) { printf("Delete shmid=%d \n", shmid); shmctl(shmid, IPC_RMID, NULL); // 删除已经存在的共享内存 } } //返回头地址 bool F_Shm::open_shm(key_t key, int blksize, int blocks) { int shmid; this->close_shm(); //1. 查看是否已经存在共享内存,如果有则删除旧的 shmid = shmget(key, 0, 0); if (shmid == -1) { return this->creat_shm(key, blksize, blocks); } //2.连接共享内存 shmhead = shmat(shmid, (void*)0, 0); //连接共享内存 if(shmhead == (void*)-1) { ERR_EXIT("shmat"); } printf("Open shmid=%d size=%u \n", shmid, sizeof(shmhead_t) + blksize*blocks); //3. 填充控制共享内存的信息 payload = (char *)((shmhead_t *)shmhead + 1); //实际负载起始位置 open = true; return true; } //关闭共享内存 void F_Shm::close_shm(void) { if(open) { shmdt(shmhead); //共享内存脱离 shmhead = NULL; payload = NULL; open = false; } } void F_Shm::write_into_shm(const void *buf) { shmhead_t *pHead = (shmhead_t *)shmhead; sem_wait(&pHead->sem_full); //是否有资源写? 可用写资源-1 sem_wait(&pHead->sem_mutex); //是否有人正在写? printf("write to shm[%d] index %d \n", pHead->shmid, pHead->rd_index); memcpy(payload + (pHead->wr_index) * (pHead->blksize), buf, pHead->blksize); pHead->wr_index = (pHead->wr_index+1) % (pHead->blocks); //写位置偏移 sem_post(&pHead->sem_mutex); //解除互斥 sem_post(&pHead->sem_empty); //可用读资源+1 } void F_Shm::read_from_shm(void *buf) { shmhead_t *pHead = (shmhead_t *)shmhead; sem_wait(&pHead->sem_empty); //检测写资源是否可用 printf("read from shm[%d] index %d \n", pHead->shmid, pHead->rd_index); memcpy(buf, payload + (pHead->rd_index) * (pHead->blksize), pHead->blksize); //读位置偏移 pHead->rd_index = (pHead->rd_index+1) % (pHead->blocks); sem_post(&pHead->sem_full); //增加可写资源 }

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

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

任务调度

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:使用BeautifulSoup库解析htm、xml文档
下一篇:Python 官宣:正式发布 Python 3.8.0!
相关文章