对于我正在开发的应用程序(在 Linux 下,但我试图保持可移植性)我需要切换到共享内存以在不同进程(和进程内的线程)之间共享数据。有一个父进程生成不同的子进程
例如,我需要让每个进程都能够使用命名信号量递增共享计数器。
在这种情况下一切正常:
#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);
}
到目前为止一切顺利:信号量和共享计数器都正常(内存中的相同地址)并且递增和重置工作正常。
程序失败只是因为将子源代码移动到一个由 exec 调用的新源文件中。共享内存和命名信号量地址不同,因此递增失败。
有什么建议吗?我使用命名信号量和命名共享内存(使用文件)来尝试获取相同的指针值。
更新:
应 Joachim 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);
}
执行此代码会导致进程阻塞(死锁)并等待无限时间。查看通常发现的地址:
father semaphore: 0x7f2fe1813000
child semahpore: 0x7f0c4c793000
father shared memory: 0x7f2fe1811000
child shared memory: 0x7ffd175cb000
删除“sem_post”和“sem_wait”一切都很好,但我需要在递增时相互排斥...
最佳答案
不要取消链接信号量。它实际上删除了信号量。
来自sem_unlink
手册页:
sem_unlink() removes the named semaphore referred to by name. The semaphore name is removed immediately. The semaphore is destroyed once all other processes that have the semaphore open close it.
这意味着一旦您在父进程中创建了信号量,就可以立即将其删除。子进程将无法找到信号量,而是创建一个新信号量。
关于c++ - fork exec 和 mmap 问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14831104/