I have a problem with the shared memory between parent and child processes generated by a fork. I know how to use shared memory with primitive type as described here.
While I do not know how to share struct that contains a pointer that can be allocated via malloc.
For instance, suppose that I have the following code took from the previous link with some modifications.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/file.h>
#include <sys/mman.h>
#include <sys/wait.h>
typedef struct Data {
char * name;
} Data;
void error_and_die(const char *msg) {
perror(msg);
exit(EXIT_FAILURE);
}
int main(int argc, char *argv[]) {
int r;
const char *memname = "sample";
const size_t region_size = sysconf(_SC_PAGE_SIZE);
int fd = shm_open(memname, O_CREAT | O_TRUNC | O_RDWR, 0666);
if (fd == -1)
error_and_die("shm_open");
r = ftruncate(fd, region_size);
if (r != 0)
error_and_die("ftruncate");
Data * data = (Data *) malloc(sizeof(data));
data->name=(char *) malloc(100*sizeof(char));
void *ptr = mmap(0, region_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (ptr == MAP_FAILED)
error_and_die("mmap");
close(fd);
ptr=(Data *) data;
pid_t pid = fork();
if (pid == 0) {
//u_long *d = (u_long *) ptr;
//*d = 0xdbeebee;
data->name="bob";
printf("CHILD child wrote %s\n", (*(Data *)ptr).name);
exit(0);
}
else {
int status;
waitpid(pid, &status, 0);
//printf("child wrote %#lx\n", *(u_long *) ptr);
printf("PARENT child wrote %s\n", (*(Data *)ptr).name);
}
r = munmap(ptr, region_size);
if (r != 0)
error_and_die("munmap");
r = shm_unlink(memname);
if (r != 0)
error_and_die("shm_unlink");
return 0;
}
I would like to change the data inside the struct between parent and child processes in order to allow IPC. How can I do?
Thank you
After fork the parent and child can update their own copies of the variables in their own way, since they dont actually share the variable. Here we show how they can share memory, so that when one updates it, the other can see the change.
Answer: Only the shared memory segments are shared between the parent process and the newly forked child process. Copies of the stack and the heap are made for the newly created process.
You need the parent to ask for the number, write it into shared memory, and tell the child via some (other) IPC mechanism that the number is ready. The child should then wake up, read the number, do the calculation, and write the answer, then notify the parent it is done simply by exiting.
Sharing data between Processes in Windows: Named Pipe and Shared Memory. Shared data is a fast way to communicate between parent and child processes. Depending on the size of the shared data, you can choose either named pipe or named shared memory.
If you're asking "how to do it with malloc()
", it is not possible, unless you write your own malloc()
implementation that allocated from a buffer in a shared memory region. That is a possible approach, but goes beyond this answer. Otherwise the memory allocated by malloc() is not shared between parent and child; each one gets it's own copy.
If you're asking "how to change the example so that it works" - simply use the memory returned by the mmap()
call.
To simplify, let's declare name
as an array in the Data
structure:
typedef struct Data {
char name[100];
} Data;
Then the main code becomes:
void *ptr = mmap(0, region_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (ptr == MAP_FAILED)
error_and_die("mmap");
close(fd);
Data * data = ptr;
pid_t pid = fork();
if (pid == 0) {
strcpy(data->name, "bob");
printf("CHILD child wrote %s\n", (*(Data *)ptr).name);
exit(0);
}
else {
int status;
waitpid(pid, &status, 0);
printf("PARENT child wrote %s\n", (*(Data *)ptr).name);
}
Output:
CHILD child wrote bob
PARENT child wrote bob
I solved by myself by following this guide and by using shmget, shmat, smhdt and shmctl instead of shm_open, mmap, munmap and shm_unlink.
In this way, I can manage dynamic shared memory as with malloc with the advantage that the memory is visible between the processes.
I report here the code as future hint.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/shm.h>
typedef struct Person {
char * name;
int * numbers;
} Person;
typedef struct Data {
Person * persons;
} Data;
int main(int argc, char *argv[]) {
Data * data;
Person * person;
key_t mykey1=5500;
key_t mykey2=5501;
key_t mykey3=5502;
key_t mykey4=5503;
key_t mykey5=5504;
int mem_id;
mem_id=shmget(mykey1,sizeof(Person),IPC_CREAT|0666);
if (mem_id<0) {
perror("error shmget");
}
person=(Person*)shmat(mem_id,(void*)0,0);
if(person == (Person*)(-1)) {
perror("error shmat");
}
mem_id=shmget(mykey2,(100*sizeof(char)),IPC_CREAT|0666);
if (mem_id<0) {
perror("error shmget 2");
}
person->name=(char *)shmat(mem_id,(void*)0,0);
if (person->name == (char *)(-1)) {
perror("error shmat 2");
}
mem_id=shmget(mykey3,(10*sizeof(int)),IPC_CREAT|0666);
if (mem_id<0) {
perror("error shmget 3");
}
person->numbers=(int *)shmat(mem_id,(void*)0,0);
if (person->numbers == (int *)(-1)) {
perror("error shmat 3");
}
mem_id=shmget(mykey4,sizeof(Data),IPC_CREAT|0666);
if (mem_id<0) {
perror("error shmget 4");
}
data=(Data*)shmat(mem_id,(void*)0,0);
if(data == (Data*)(-1)) {
perror("error shmat 4");
}
mem_id=shmget(mykey5,(10*sizeof(int)),IPC_CREAT|0666);
if (mem_id<0) {
perror("error shmget 5");
}
data->persons=(Person *)shmat(mem_id,(void*)0,0);
if (data->persons == (Person *)(-1)) {
perror("error shmat 5");
}
pid_t pid = fork();
if (pid == 0) {
person->name="bob";
for(int i=0; i<10; i++) {
person->numbers[i]=i;
}
data->persons[0]=*person;
data->persons[1].name="alice";
printf("CHILD child wrote %s\n", person->name);
exit(0);
}
else {
int status;
waitpid(pid, &status, 0);
printf("PARENT child wrote %s\n", person->name);
for(int i=0; i<10; i++) {
printf("%d\n",person->numbers[i]);
}
printf("PARENT child wrote %s\n", data->persons[0].name);
for(int i=0; i<10; i++) {
printf("%d\n",data->persons[0].numbers[i]);
}
printf("PARENT child wrote %s\n", data->persons[1].name);
}
shmdt(person);
shmdt(data);
shmctl(mem_id,IPC_RMID,0);
return 0;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With