對於我正在開發的應用程序(在Linux下,但我試圖保持可移植性),我需要切換到共享內存以跨不同進程(以及進程內的線程)共享數據。有一個父進程產生不同的孩子fork exec和mmap問題
我需要例如讓每個進程能夠使用命名的信號量遞增共享計數器。
在這種情況下,一切都很好:
#include <sys/mman.h>
#include <sys/wait.h>
#include <semaphore.h>
#include <fcntl.h>
#include <iostream>
#include <stdlib.h>
#include <string.h>
using namespace std;
#define SEM_NAME "/mysem"
#define SM_NAME "tmp_sm.txt"
int main(){
int fd, nloop, counter_reset;
int *smo;
sem_t *mutex;
nloop = 100;
counter_reset = 1000;
if (fork() == 0) {
/* child */
/* create, initialize, and unlink semaphore */
mutex = sem_open(SEM_NAME, O_CREAT, 0777, 1);
//sem_unlink(SEM_NAME);
/* open file, initialize to 0, map into memory */
fd = open(SM_NAME, O_RDWR | O_CREAT);
smo = (int *) mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
close(fd);
/* INCREMENT */
for (int i = 0; i < nloop; i++) {
sem_wait(mutex);
cout << "child: " << (*smo)++ << endl;
if(*smo>=counter_reset){
(*smo)=0;
}
sem_post(mutex);
}
exit(0);
}
/* parent */
/* create, initialize, and unlink semaphore */
mutex = sem_open(SEM_NAME, O_CREAT, 0777, 1);
sem_unlink(SEM_NAME);
/* open file, initialize to 0, map into memory */
fd = open(SM_NAME, O_RDWR | O_CREAT);
smo = (int *) mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
close(fd);
/* INCREMENT */
for (int i = 0; i < nloop; i++) {
sem_wait(mutex);
cout << "parent: " << (*smo)++ << endl;
if(*smo>=counter_reset){
(*smo)=0;
}
sem_post(mutex);
}
exit(0);
}
到目前爲止好:兩個信號燈和共享計數器都ok(在內存地址相同)和增量和復位做工精細。
程序僅僅通過將子代碼源代碼移動到由exec調用的新源文件而失敗。共享內存和命名信號地址不同,因此增量失敗。
有什麼建議嗎?我使用命名信號量和命名共享內存(使用文件)嘗試獲取相同的指針值。
UPDATE:
由勒夫Pileborg請求,這是在 「服務器側」 改進遵守上述原代碼:
...
if (fork() == 0) {
/* child */
/*spawn child by execl*/
char cmd[] = "/path_to_bin/client";
execl(cmd, cmd, (char *)0);
cerr << "error while istantiating new process" << endl;
exit(EXIT_FAILURE);
}
...
這是 「客戶機」 的源代碼:
#include <sys/mman.h>
#include <sys/wait.h>
#include <semaphore.h>
#include <fcntl.h>
#include <iostream>
#include <stdlib.h>
using namespace std;
#define SEM_NAME "/mysem"
#define SM_NAME "tmp_ssm.txt"
int main(){
int nloop, counter_reset;
int *smo;
sem_t *mutex;
/* create, initialize, and unlink semaphore */
mutex = sem_open(SEM_NAME, O_CREAT, 0777, 1);
//sem_unlink(SEM_NAME);
/* open file, initialize to 0, map into memory */
int fd = open(SM_NAME, O_RDWR | O_CREAT);
smo = (int *) mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
close(fd);
nloop=100;
counter_reset=1000;
/* INCREMENT */
for (int i = 0; i < nloop; i++) {
sem_wait(mutex);
cout << "child: " << (*smo)++ << endl;
if(*smo>=counter_reset){
(*smo)=0;
}
sem_post(mutex);
}
exit(0);
}
執行此代碼會導致進程阻塞(死鎖)並等待無限時間。看着他們tipically發現地址:
father semaphore: 0x7f2fe1813000
child semahpore: 0x7f0c4c793000
father shared memory: 0x7f2fe1811000
child shared memory: 0x7ffd175cb000
去除「sem_post」和「sem_wait」一切都很好,但我需要相互排阻而遞增......
你不應該在實際的地址上看起來很難,因爲這是不同的過程,所以這些將會有所不同。另外,我不希望在父進程中調用sem_unlink?另外,由於'mmap'返回-1,你應該檢查錯誤代碼('errno',或者用'perror'打印出來)。 – 2013-02-12 13:40:58
哦,順便說一句,你在調用'shm_open'時設置了錯誤的模式。它應該是一個文件模式,就像在調用'sem_open'時一樣。 – 2013-02-12 13:44:27
@JoachimPileborg:沒有sem_unlink沒有更多的叫...我沒有修改原始代碼的追蹤變更,但我現在要添加評論...我要檢查你告訴我的一切... – schu 2013-02-12 13:44:43