fork exec和mmap问题

时间:2013-02-12 11:07:37

标签: c++ linux exec fork mmap

对于我正在开发的应用程序(在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'一切都很好,但我需要在增加时互相排斥......

1 个答案:

答案 0 :(得分:2)

不要取消信号量的链接。它实际上删除了信号量。

sem_unlink手册页:

  

sem_unlink()删除name引用的命名信号量。信号量名称立即被删除。一旦所有其他具有信号量打开的进程关闭它,信号量就会被破坏。

这意味着一旦您在父进程中创建了信号量,就会立即将其删除。然后子进程将无法找到信号量,而是创建一个新的信号量。