简体   繁体   中英

Updating shared memory by different process

I'm writing some code for a project and I have an issue when I try to update an area of shared memory with another process. Basically one process create a shared memory, then it creates one child that, using execve, execute a process the aim of which is to update that shared memory knowing its key. At the end the main process prints all the datas from the shm to stdout.

At that point I have noticed that shm has not been updated. I can't understand why. I've tried with regular assignment ( = ) or assigning every field with a function ( updatef ), but it doesn't work. (Of course in the real program I used semaphores to regulate the access to shm, i wrote this code to minimize the code to see the problem)

Process t:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/signal.h>
#include <fcntl.h>
#include <stdarg.h>
#include <errno.h>
#include <time.h>

#define mykey 100
#define maxname 100
#define shmsz 5
#define perms 0666

struct pdata{
    pid_t ppid;
    char ptype;
    char pname[maxname];
    unsigned long pgenome;
};

void updatef(struct pdata a, struct pdata p){
    a.ppid = p.ppid;
    a.ptype = p.ptype;
    strcpy(a.pname, p.pname);
    a.pgenome = p.pgenome;
}

int main(){
    int shmid;
    struct pdata *addr;

    shmid = shmget(mykey, sizeof(struct pdata) * shmsz, IPC_CREAT | perms);
    addr = (struct pdata*) shmat(shmid, NULL, 0);
    for(int i=0; i<shmsz; i++){
        addr[i].ppid = -1;
    }
    switch(fork()){
        case 0:
            {
            char *args[] = {"u", NULL};
            execve("u", args, NULL);
            }
            break;
    }
    sleep(2);
    for(int i=0; i<shmsz; i++){
        printf("%d %c %s %lu\n", addr[i].ppid, addr[i].ptype, addr[i].pname,    addr[i].pgenome);
    }
    shmdt(addr);
    shmctl(shmid, IPC_RMID, 0);

    return 0;
    }

Process u:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/signal.h>
#include <fcntl.h>
#include <stdarg.h>
#include <errno.h>
#include <time.h>

#define mykey 100
#define maxname 100
#define shmsz 5
#define perms 0666

struct pdata{
   pid_t ppid;
   char ptype;
   char pname[maxname];
   unsigned long pgenome;
};

void updatef(struct pdata a, struct pdata p){
    a.ppid = p.ppid;
    a.ptype = p.ptype;
    strcpy(a.pname, p.pname);
    a.pgenome = p.pgenome;
}

int main(){
    int shmid;
    struct pdata *addr;
    struct pdata p;
    shmid = shmget(mykey, sizeof(struct pdata) * shmsz, perms);
    addr = (struct pdata*) shmat(shmid, NULL, 0);
    p.ppid = getpid();
    p.ptype = 'A';
    strncpy(p.pname, "PIPPO", maxname);
    p.pgenome = 10;

    for(int i=0; i<shmsz; i++){
        updatef(addr[i], p);
    }

    shmdt(addr);

return 0;
}

Short answer is of course passing pointer instead of value and that'll do

updatef(&arr[i], p);

Long answer lies in pass by value and pass by reference, when updatef is called with addr[i] as in

updatef(arr[i], p);

essentially the value is copied to calling function and never gets reflected to attached pointer viz addr as a result the original addr pointer get unchanged on the other hand when we pass the address like

updatef(&addr[i], p); 
//or
updatef(addr+i, p);

reference is passed which inturn will update the contents pointed to by addr+i pointer

to add on IMO splitting the code will make this more presentable and readable and maintainable and bla bla bla here is a bit

File 1 - sh , keep shared and global data here

#ifndef S_H_INCLUDED
#define S_H_INCLUDED

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/signal.h>
#include <fcntl.h>
#include <stdarg.h>
#include <errno.h>
#include <time.h>

#define mykey 100
#define maxname 100
#define shmsz 5
#define perms 0666

struct pdata{
    pid_t ppid;
    char ptype;
    char pname[maxname];
    unsigned long pgenome; };



#endif

tc

#include "s.h" // include global header here

int main(){
    int shmid;
    struct pdata *addr;

    shmid = shmget(mykey, sizeof(struct pdata) * shmsz, IPC_CREAT | perms);
    addr = (struct pdata*) shmat(shmid, NULL, 0);
    for(int i=0; i<shmsz; i++){
        addr[i].ppid = -1;
    }
    switch(fork()){
        case 0:
            {
            char *args[] = {"u", NULL};
            execve("u", args, NULL);
            }
            break;
    }
    sleep(2);
    for(int i=0; i<shmsz; i++){
        printf("%d %c %s %lu\n", addr[i].ppid, addr[i].ptype, addr[i].pname,    addr[i].pgenome);
    }
    shmdt(addr);
    shmctl(shmid, IPC_RMID, 0);

    return 0;
    }

uc

#include "s.h" // common included here

static void updatef(struct pdata *a, struct pdata p){
    a->ppid = p.ppid;
    a->ptype = p.ptype;
    strcpy(a->pname, p.pname);
    a->pgenome = p.pgenome;
}

int main(){
    int shmid;
    struct pdata *addr;
    struct pdata p;
    shmid = shmget(mykey, sizeof(struct pdata) * shmsz, perms);
    addr = (struct pdata*) shmat(shmid, NULL, 0);
    p.ppid = getpid();
    p.ptype = 'A';
    strncpy(p.pname, "PIPPO", maxname);
    p.pgenome = 10;

    for(int i=0; i<shmsz; i++){
        updatef(addr+i, p);
    }

    shmdt(addr);
    return 0;
}

and the final build step

gcc t.c -o t
gcc u.c -o u

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM