稍安勿躁。
先解決問題
如果你是在網上輾轉而不得其解,那就來我這兒吧。
之前那篇寫的比較急,講的還是蠻有條理的,就是東西少了點,這篇一次性寫完。
那天,我和共享內存、shmid不眠不休只吃一點喝一點奮戰了十個小時,只為了把我的項目進度趕在大家前面,卻被進程間通信始終無法打通而攔住。解決問題之后,有感而作。
如果放在今天,我會選擇采用TCP流協議的方式來進行進程間通信,詳情:你會不會分布式系統進程間通信
不過我們現在講的是shm,好。
以下內容基于在一個進程里至少準備掛兩個共享內存,一個用來發,一個用來收
既然用到shm,那自然和key值要打交道。
key值有fotk函數生成,如果對ftok函數不熟,有空可以看一下這篇:ftok
講的是極好的,不是我寫的。
我遇到的第一個問題,是:
不同參數的ftok生成同樣的shmid值
。
為什么呢?不知道。
但是我還不算傻,至少知道做個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小時內刪除侵權內容。
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。