Reputation: 409
I'm trying to share a pointer of defined class between the parent and the forked child through shared memory.
so in parent's main i create the pointer
mydata *p;
Reader::GetInstance()->Read(p, i+1);
pid = fork();
if (pid == -1){
cout << "error on fork"<<endl;
}else if (pid == 0){
cout << "i will fork now" <<endl;
const char * path = "./mydatamanager";
execl (path, "-", (char *)0);
break;
}else {
writer(shmid, p);
}
writer contains this
void writer(int shmid , mydata * p)
{
void *shmaddr;
shmaddr = shmat(shmid, (void *)0, 0);
if((int)shmaddr == -1)
{
perror("Error in attach in writer");
exit(-1);
}
else
{
memcpy( shmaddr, p, sizeof(*p) );
}
}
and my data is
class mydara {
public:
int var1;
int var2;
int var3;
int var4;
int var5;
int var6;
char *var7;
mydata (int v2, int v3,char *v7, int v6){
var2 = v2;
var3 = v3;
var7 =new char[128];
strcpy(var7, v7);
var6 = v6;
var4 = 0;
var5 = 0;
}
};
and in the mydatamanager i get this pointer this way
void reader(int shmid, mydata *& p)
{
cout << "in reader" << endl;
void *shmaddr;
//sleep(3);
shmaddr = shmat(shmid, (void *)0, SHM_RDONLY|0644);
if((int)shmaddr == -1)
{
perror("Error in reader");
exit(-1);
}
else
{
cout << "in else "<< endl;
p = (mydata*) shmaddr;
cout <<"shared memory address is " <<shmaddr <<endl;
cout <<"var5 "<< p->var5<< endl;
cout <<"var2 "<< p->var2<< " match with "<<getpid() << "?" << endl;
cout <<"var3 "<< p->var3<< endl;
cout <<"var4 "<< p->var4<< endl;
cout <<"var7 "<< p->var7<< endl; // the
//shmdt(shmaddr);
}
}
and mydatamanager main :
int main()
{
cout << "in main" <<endl;
int shmid;
shmid = shmget(IPC_PRIVATE, 4096, IPC_CREAT|0644);
cout << "in advanced point" <<endl;
sleep(1);
mydata * p;
reader (shmid, p);
cout << p->var7 <<endl;
return 0;
}
the results are always 0. how can i share this pointer through the parent and the child and where is the fault in my code?
Upvotes: 2
Views: 4378
Reputation: 14750
The simplest way to handle your problem is to create a semaphore in the parent process before the fork
, have the child process try to acquire it before the read (instead of doing a sleep
) and the parent process release it after the write.
First, here's functions to create, destroy, and retreive the id of the semaphore:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int create_semaphore(const char *path, char id, int count){
key_t k = ftok(path, id);
semid = semget(k, 1, IPC_CREAT | IPC_EXCL | 0600);
semctl(semid, 0, SET_VAL, count);
return semid;
}
int destroy_semaphore(int semid){
semctl(semid, 0, IPC_RMID, 0);
}
int get_semaphore(const char *path, char id){
key_t k = ftok(path, id);
semid = semget(k, 1, 0600);
return semid;
}
Now we need a function to acquire it, and another one to release it:
void acquire_semaphore(int semid){
sembuf op;
op.sem_num = O;
op.sem_op = -1;
op.sem_flg = 0;
semop(semid,&op,1);
}
void release_semaphore(int semid){
sembuf op;
op.sem_num = 0;
op.sem_op = 1;
op.sem_flg = 0;
semop(semid,&op,1);
}
With these boilerplate functions in place, you should be able to synchronize your processes.
So, you will need to provide a path and a unique id (in the form of a simple character) to create and identify your semaphore. If you already used ftok
to create your shared memory id (shmid
), you should understand the idea. Otherwise, just make sure that both values are the same within both processes.
In your writer code, put the following line:
semid = create_semaphore(argv[0], 'S', 0);
right before the pid = fork();
line, to create and acquire the semaphore at the same time.
Add the line:
release_semaphore(semid);
after the writer(shmid, mydata);
instruction to release the semaphore. You will also need to declare semid
somewhere in scope. I used the writer program path to create the semaphore, which is good practice to ensure that no other process has already used our path. The only catch is that you need to make sure that reader will use that same path. You can hardcode that value somewhere in reader's code, or better yet, pass it from writer in the execl
parameters (left as an exercise).
Assuming that path
is known in reader, all is left to do is to acquire the the semaphore likeso:
semid = get_semaphore(path, 'S');
acquire_semaphore(semid);
destroy_semaphore(semid);
before the line reader(shmid, mydata);
in the main
function of reader.
As other posts have said, sharing class instances through a shared memory segment is usually a very bad idea. It is much safer
to pass simple struct
data, and reconstruct your object on the reader side (look up serialization and marshalling on the net for more information).
Ask if you have problems with this (untested) code.
Merry Christmas!
Upvotes: 0
Reputation: 129524
First of all, you are not synchronising anything. So how do you know which runs first, the reader or the writer. Memory is bound to be zero in a newly allocated block, so hence you get zero as a result.
Any shared memory must ensure that the reader doesn't read until the writer has completed (at least part of) the writing process, at the very least.
Beware of sharing classes - you must not use virtual functions, as that will almost certainly do something ohterthan what you expect (crash, most likely, but other options are available, none of them particularly pleasant)
Upvotes: 1
Reputation: 1139
Hi i had a IPC task some weeks ago and finally decided to use boost.
http://blog.wolfgang-vogl.com/?p=528
Upvotes: 1