我试图通过共享内存在父级和分叉子级之间共享已定义类的指针。
所以在父母的主要创建指针
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包含此
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) );
}
}
我的数据是
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;
}
};
并且在mydatamanager中我以这种方式得到这个指针
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);
}
}
和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;
}
结果始终为0。 我如何通过父和子共享此指针以及我的代码中的错误在哪里?
答案 0 :(得分:1)
我几周前有一项IPC任务,最后决定使用boost。
答案 1 :(得分:1)
首先,你没有同步任何东西。那你怎么知道哪个先跑,读者或作家。在新分配的块中,内存必然为零,因此结果为零。
任何共享内存必须确保读者在读者完成(至少部分)写入过程之前不会阅读。
小心分享课程 - 你不能使用虚拟功能,因为这几乎肯定会做一些你所期望的事情(崩溃,很可能,但其他选项都可用,没有一个特别令人愉快)
答案 2 :(得分:0)
处理问题的最简单方法是在 fork
之前在父进程中创建一个信号量,让子进程在之前尝试获取它读取(而不是执行sleep
)并且父进程在写入之后将其释放。
首先,这里有创建,销毁和检索信号量id的函数:
#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;
}
现在我们需要一个函数来获取它,另一个函数来释放它:
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);
}
使用这些样板功能,您应该能够同步您的过程。
因此,您需要提供路径和唯一ID(以简单字符的形式)来创建和识别您的信号量。如果您已使用ftok
创建共享内存ID(shmid
),则应了解该想法。否则,只需确保两个进程中的两个值都相同。
在您的编写器代码中,输入以下行:
semid = create_semaphore(argv[0], 'S', 0);
在pid = fork();
行之前,同时创建和获取信号量。
添加以下行:
release_semaphore(semid);
在发出信号量的writer(shmid, mydata);
指令之后。您还需要在范围内的某处声明semid
。我使用编写器程序路径来创建信号量,这是确保没有其他进程已经使用我们的路径的好习惯。唯一的问题是你需要确保读者使用相同的路径。您可以在读者代码中的某个位置对该值进行硬编码,或者更好的是,将其从execl
参数中的作者传递(左侧作为练习)。
假设读者已知path
,剩下要做的就是获取信号量似的:
semid = get_semaphore(path, 'S');
acquire_semaphore(semid);
destroy_semaphore(semid);
在读者reader(shmid, mydata);
函数中的行main
之前
正如其他帖子所说,通过共享内存段共享类实例通常是非常糟糕的主意。它更安全
传递简单的struct
数据,并在阅读器端重建您的对象(在网上查找序列化和编组以获取更多信息)。
询问您是否遇到此(未经测试)代码的问题。
圣诞快乐!