user-0 提问: 在父子进程间使用共享内存(共享内容含指针)

回复:
user: user-1
content: 《Windows核心编程》

user: user-2
content: 引用 12 楼 u012889234 的回复:[quote=引用 10 楼 wangzuxi 的回复:] [quote=引用 9 楼 u012889234 的回复:] 如果我现在要创建8个子进程，每个子进程与父进程之间有一个共享区域。要做到它们相互隔离。这=这样会不会有问题？ 我推荐你还是在父进程mmap一块匿名共享内存，然后fork出子进程，这样子进程也可以共享父进程创建的共享内存，而且指针也一样，可以把共享内存中的指针保存到共享内存中。 [/quote] 我试了这种方法，，跟原来的效果是一样的。。我这个指向数据包的指针(tEthpkt *)是由驱动传上来的。  static int vsmart6_func(pid_t pid) {     int index, vindex;     for(index = 0; index < MAX_SHARED_CNT; index++)     {         if(PktQue[index] != NULL && PktQue[index]->pid == pid)         {             printf("pid: %d\n", PktQue[index]->pid);             vindex = index;             break;         }     } ////////////////////////////////////////////////////////////////////// //开始处理对应的数据包队列中的数据包     proc_pkt_out_vs(PktQue[vindex]);      return 0; }   int vsmart6_create() {     int index, sindex, pindex;     pid_t pid;     pid_t cpid;          if(cur_vsmart6_cnt >= MAX_VSMART6_CNT)     {         printf("\n******VSmart6 has reached its limit!\n");         return -1;     }      for(index = 0; index < MAX_SHARED_CNT; index++)     {         if(PktQue[index] == NULL)         {             sindex = index;             break;         }     }      PktQue[sindex] = (tPktQue *)mmap(NULL, sizeof(tPktQue), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0); //初始化     pid = fork();     if(pid == 0)  //子进程     {         sleep(2);  //等待父进程对共享区域初始化完成         cpid = getpid();         vsmart6_func(cpid);     }     PktQue[sindex]->pid = pid;                        //init mutex      PktQue[sindex]->V6_out_mutex = (tMutex *)mutex_create();      PktQue[sindex]->V4_out_mutex = (tMutex *)mutex_create();      PktQue[sindex]->V4_in_mutex  = (tMutex *)mutex_create();      PktQue[sindex]->V6_in_mutex  = (tMutex *)mutex_create();             //init para      PktQue[sindex]->V6_out_curcnt = 0;      PktQue[sindex]->V6_out_head   = 0;      PktQue[sindex]->V6_out_tail   = 0;       PktQue[sindex]->V4_out_curcnt = 0;      PktQue[sindex]->V4_out_head   = 0;      PktQue[sindex]->V4_out_tail   = 0;       PktQue[sindex]->V4_in_curcnt  = 0;      PktQue[sindex]->V4_in_head    = 0;      PktQue[sindex]->V4_in_tail    = 0;       PktQue[sindex]->V6_in_curcnt  = 0;      PktQue[sindex]->V6_in_head    = 0;      PktQue[sindex]->V6_in_tail    = 0;       //init package     for(pindex = 0; pindex < MAX_QUE_SIZE; pindex++)     {          PktQue[sindex]->V6_out_queue[pindex] = NULL;          PktQue[sindex]->V4_out_queue[pindex] = NULL;          PktQue[sindex]->V4_in_queue[pindex]  = NULL;          PktQue[sindex]->V6_in_queue[pindex]  = NULL;     }  //////////////////////////////////////////////////////////////////////////// //在相应的MyVsmart6中更新配置   for test #if 1         char name[16] = "test";         memcpy(MyVsmart6[sindex].name, name, strlen(name));         MyVsmart6[sindex].pid = pid;         MyVsmart6[sindex].prefA_count = 1;         MyVsmart6[sindex].PrefA_Len[0] = 6; /*-48/8-*/         inet_pton(AF_INET6, "2001:da8:b001::", (char *)(MyVsmart6[sindex].prefA[0]));         MyVsmart6[sindex].prefA_nat_start = gn_htonl(inet_addr("10.8.10.132"));         MyVsmart6[sindex].prefA_nat_end   = gn_htonl(inet_addr("10.8.10.133"));         MyVsmart6[sindex].prefA_natipcnt = MyVsmart6[sindex].prefA_nat_end - MyVsmart6[sindex].prefA_nat_start + 1; #endif ////////////////////////////////////////////////////////////////////////////      return 0; }   void proc_pkt_out_vs(tPktQue * pPktQue) {     UINT4   head;     UINT4   tail;     tEthpkt *  pkthdr = NULL;      while(1)     {         mutex_lock(pPktQue->V6_out_mutex);         head = pPktQue->V6_out_head;         tail = pPktQue->V6_out_tail;         if(head == tail)         {             mutex_unlock(pPktQue->V6_out_mutex);             //printf("\n****V6_out_queue is Empty!\n");             continue;         }          printf("head: %d, tail: %d\n", head, tail);         pkthdr = pPktQue->V6_out_queue[head];          printf("after: %p\n", pkthdr); #if 0         printf("IP: %x:%x:%x:%x--------->%x:%x:%x:%x\n", \             gn_ntohl(pkthdr->pIpv6->src1[0]), gn_ntohl(pkthdr->pIpv6->src1[1]), \             gn_ntohl(pkthdr->pIpv6->src1[2]), gn_ntohl(pkthdr->pIpv6->src1[3]), \             gn_ntohl(pkthdr->pIpv6->dest1[0]), gn_ntohl(pkthdr->pIpv6->dest1[1]), \             gn_ntohl(pkthdr->pIpv6->dest1[2]), gn_ntohl(pkthdr->pIpv6->dest1[3])); #endif                     pPktQue->V6_out_head = (head + 1) % MAX_QUE_SIZE;         mutex_unlock(pPktQue->V6_out_mutex);         //usleep(100);         sleep(2);        }    }   /* before: 0x7f10fec8e060 head: 0, tail: 1 after: 0x7f10fec8e060  before: 0x7f10fec8e060 head: 1, tail: 2 after: 0x7f10fec8e060  before: 0x7f10fec8e060 head: 2, tail: 3 after: 0x7f10fec8e060  before: 0x7f10fec8e060 head: 3, tail: 4 after: 0x7f10fec8e060  */ [/quote] 你每次从队列中取出来的指针都一样，你的驱动收数据包入队列是在哪里做的，看看入队列是不是这样入的。而且这个指针(tEthpkt *)也要保证每个进程都一样并能访问，这样放到共享内存才有意义。

user: user-0
content: 引用 10 楼 wangzuxi 的回复:[quote=引用 9 楼 u012889234 的回复:] 如果我现在要创建8个子进程，每个子进程与父进程之间有一个共享区域。要做到它们相互隔离。这=这样会不会有问题？ 我推荐你还是在父进程mmap一块匿名共享内存，然后fork出子进程，这样子进程也可以共享父进程创建的共享内存，而且指针也一样，可以把共享内存中的指针保存到共享内存中。 [/quote] 我试了这种方法，，跟原来的效果是一样的。。我这个指向数据包的指针(tEthpkt *)是由驱动传上来的。  static int vsmart6_func(pid_t pid) {     int index, vindex;     for(index = 0; index < MAX_SHARED_CNT; index++)     {         if(PktQue[index] != NULL && PktQue[index]->pid == pid)         {             printf("pid: %d\n", PktQue[index]->pid);             vindex = index;             break;         }     } ////////////////////////////////////////////////////////////////////// //开始处理对应的数据包队列中的数据包     proc_pkt_out_vs(PktQue[vindex]);      return 0; }   int vsmart6_create() {     int index, sindex, pindex;     pid_t pid;     pid_t cpid;          if(cur_vsmart6_cnt >= MAX_VSMART6_CNT)     {         printf("\n******VSmart6 has reached its limit!\n");         return -1;     }      for(index = 0; index < MAX_SHARED_CNT; index++)     {         if(PktQue[index] == NULL)         {             sindex = index;             break;         }     }      PktQue[sindex] = (tPktQue *)mmap(NULL, sizeof(tPktQue), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0); //初始化     pid = fork();     if(pid == 0)  //子进程     {         sleep(2);  //等待父进程对共享区域初始化完成         cpid = getpid();         vsmart6_func(cpid);     }     PktQue[sindex]->pid = pid;                        //init mutex      PktQue[sindex]->V6_out_mutex = (tMutex *)mutex_create();      PktQue[sindex]->V4_out_mutex = (tMutex *)mutex_create();      PktQue[sindex]->V4_in_mutex  = (tMutex *)mutex_create();      PktQue[sindex]->V6_in_mutex  = (tMutex *)mutex_create();             //init para      PktQue[sindex]->V6_out_curcnt = 0;      PktQue[sindex]->V6_out_head   = 0;      PktQue[sindex]->V6_out_tail   = 0;       PktQue[sindex]->V4_out_curcnt = 0;      PktQue[sindex]->V4_out_head   = 0;      PktQue[sindex]->V4_out_tail   = 0;       PktQue[sindex]->V4_in_curcnt  = 0;      PktQue[sindex]->V4_in_head    = 0;      PktQue[sindex]->V4_in_tail    = 0;       PktQue[sindex]->V6_in_curcnt  = 0;      PktQue[sindex]->V6_in_head    = 0;      PktQue[sindex]->V6_in_tail    = 0;       //init package     for(pindex = 0; pindex < MAX_QUE_SIZE; pindex++)     {          PktQue[sindex]->V6_out_queue[pindex] = NULL;          PktQue[sindex]->V4_out_queue[pindex] = NULL;          PktQue[sindex]->V4_in_queue[pindex]  = NULL;          PktQue[sindex]->V6_in_queue[pindex]  = NULL;     }  //////////////////////////////////////////////////////////////////////////// //在相应的MyVsmart6中更新配置   for test #if 1         char name[16] = "test";         memcpy(MyVsmart6[sindex].name, name, strlen(name));         MyVsmart6[sindex].pid = pid;         MyVsmart6[sindex].prefA_count = 1;         MyVsmart6[sindex].PrefA_Len[0] = 6; /*-48/8-*/         inet_pton(AF_INET6, "2001:da8:b001::", (char *)(MyVsmart6[sindex].prefA[0]));         MyVsmart6[sindex].prefA_nat_start = gn_htonl(inet_addr("10.8.10.132"));         MyVsmart6[sindex].prefA_nat_end   = gn_htonl(inet_addr("10.8.10.133"));         MyVsmart6[sindex].prefA_natipcnt = MyVsmart6[sindex].prefA_nat_end - MyVsmart6[sindex].prefA_nat_start + 1; #endif ////////////////////////////////////////////////////////////////////////////      return 0; }   void proc_pkt_out_vs(tPktQue * pPktQue) {     UINT4   head;     UINT4   tail;     tEthpkt *  pkthdr = NULL;      while(1)     {         mutex_lock(pPktQue->V6_out_mutex);         head = pPktQue->V6_out_head;         tail = pPktQue->V6_out_tail;         if(head == tail)         {             mutex_unlock(pPktQue->V6_out_mutex);             //printf("\n****V6_out_queue is Empty!\n");             continue;         }          printf("head: %d, tail: %d\n", head, tail);         pkthdr = pPktQue->V6_out_queue[head];          printf("after: %p\n", pkthdr); #if 0         printf("IP: %x:%x:%x:%x--------->%x:%x:%x:%x\n", \             gn_ntohl(pkthdr->pIpv6->src1[0]), gn_ntohl(pkthdr->pIpv6->src1[1]), \             gn_ntohl(pkthdr->pIpv6->src1[2]), gn_ntohl(pkthdr->pIpv6->src1[3]), \             gn_ntohl(pkthdr->pIpv6->dest1[0]), gn_ntohl(pkthdr->pIpv6->dest1[1]), \             gn_ntohl(pkthdr->pIpv6->dest1[2]), gn_ntohl(pkthdr->pIpv6->dest1[3])); #endif                     pPktQue->V6_out_head = (head + 1) % MAX_QUE_SIZE;         mutex_unlock(pPktQue->V6_out_mutex);         //usleep(100);         sleep(2);        }    }   /* before: 0x7f10fec8e060 head: 0, tail: 1 after: 0x7f10fec8e060  before: 0x7f10fec8e060 head: 1, tail: 2 after: 0x7f10fec8e060  before: 0x7f10fec8e060 head: 2, tail: 3 after: 0x7f10fec8e060  before: 0x7f10fec8e060 head: 3, tail: 4 after: 0x7f10fec8e060  */

user: user-0
content: 引用 10 楼 wangzuxi 的回复:[quote=引用 9 楼 u012889234 的回复:] 如果我现在要创建8个子进程，每个子进程与父进程之间有一个共享区域。要做到它们相互隔离。这=这样会不会有问题？ 我推荐你还是在父进程mmap一块匿名共享内存，然后fork出子进程，这样子进程也可以共享父进程创建的共享内存，而且指针也一样，可以把共享内存中的指针保存到共享内存中。 [/quote]  嗯，， 我都做下实验。

user: user-2
content: 引用 9 楼 u012889234 的回复:如果我现在要创建8个子进程，每个子进程与父进程之间有一个共享区域。要做到它们相互隔离。这=这样会不会有问题？ 我推荐你还是在父进程mmap一块匿名共享内存，然后fork出子进程，这样子进程也可以共享父进程创建的共享内存，而且指针也一样，可以把共享内存中的指针保存到共享内存中。

user: user-0
content: 如果我现在要创建8个子进程，每个子进程与父进程之间有一个共享区域。要做到它们相互隔离。这=这样会不会有问题？

user: user-0
content: CLONE_VM | CLONE_SIGHAND | CLONE_FS | CLONE_FILES;  这些参数就指定共享地址空间。就不用共享了！！！

user: user-2
content: 引用 6 楼 wangzuxi 的回复:[quote=引用 3 楼 u012889234 的回复:] [quote=引用 1 楼 wangzuxi 的回复:] [quote=引用 楼主 u012889234 的回复:] 比如有这样一个结构体   #define MAX_QUE_LEN 100  //定义数据包缓存队列 typedef struct _t_pkt_queue {     UINT4       V6_out_head;     UINT4       V6_out_tail;     UINT4       V6_out_curcnt;     tEthpkt *   V6_out_queue[MAX_QUE_LEN]; }tPktQue;  tEthpkt  *  是指向一个数据包的指针。 在父子进程间将其共享。在子进程中 (tEthpkt *)指针不为空，但是为什么不能对其进行操作？ Linux下在父进程用mmap创建匿名共享内存，共享内存的地址在父进程和子进程是一样的，父子进程都可以直接修改共享内存中的数据。 你说的子进程不能对其进行操作是什么意思？是取不到想要的数据还是修改了数据父进程看不见？ 你是怎么创建共享内存的？[/quote]    shmid = shmget(IPC_PRIVATE, sizeof(tPktQue), IPC_CREAT|0660);     if(shmid <= 0)     {         printf("\n***Create a shared memory Fail!\n");         return -1;     }     stacksize = getpagesize();     stack = malloc(stacksize);     if(stack == NULL)     {         printf("\n***Malloc For Child Process stack Failed!\n");         return -1;     }     childstack = stack + stacksize;     flags = CLONE_NEWPID|CLONE_NEWNS;     pid = clone(vdev_func, childstack, flags, (void *)shmid);     shmaddr = (char *)shmat(shmid, NULL, 0);     PktQue[i] = (tPktQue *)shmaddr;   //这里PktQue[i] 是一个指向tPktQue  的指针。   vdev_func子进程的调用函数。 在子进程中  shmaddr = (char *)shmat(shmid, NULL, 0); PktQue[i] = (tPktQue *)shmaddr;  比如对 PktQue[i] ->V6_out_queue[0]操作。操作不了。但其不为空。[/quote] 你都用clone了，可以不用shmget和shmat了。看一下我写的测试代码：  #define _GNU_SOURCE #include <sched.h>  #include <stdio.h> #include <stdlib.h> #include <unistd.h>  int data = 10; char *str = NULL;  int child_process(void *args) {     printf("Child process %d, data %d, str: %s\n", getpid(), data, str);     data = 20;     str = "child str";     printf("Child process %d, data %d, str: %s\n", getpid(), data, str);     while (1) {         sleep(1);     } }  int main(int argc, char *argv[]) {     void *stack = (void *)malloc(16384);     int clone_flag = CLONE_VM | CLONE_SIGHAND | CLONE_FS | CLONE_FILES;     str = "parent str";          clone(child_process, stack+16384, clone_flag, NULL);     printf("Parent process %d, data %d, str: %s\n", getpid(), data, str);     sleep(1);     while (1) {         sleep(1);     }      return 0; }  运行后输出： Child process 4517, data 10, str: parent str Child process 4517, data 20, str: child str Parent process 4516, data 20, str: child str [/quote] 错了，sleep(1)是让子进程先运行再打印，应该在第29行printf之前：  #define _GNU_SOURCE #include <sched.h>   #include <stdio.h> #include <stdlib.h> #include <unistd.h>   int data = 10; char *str = NULL;   int child_process(void *args) {     printf("Child process %d, data %d, str: %s\n", getpid(), data, str);     data = 20;     str = "child str";     printf("Child process %d, data %d, str: %s\n", getpid(), data, str);     while (1) {         sleep(1);     } }   int main(int argc, char *argv[]) {     void *stack = (void *)malloc(16384);     int clone_flag = CLONE_VM | CLONE_SIGHAND | CLONE_FS | CLONE_FILES;     str = "parent str";           clone(child_process, stack+16384, clone_flag, NULL);     sleep(1);     printf("Parent process %d, data %d, str: %s\n", getpid(), data, str);     while (1) {         sleep(1);     }       return 0; }

user: user-2
content: 引用 3 楼 u012889234 的回复:[quote=引用 1 楼 wangzuxi 的回复:] [quote=引用 楼主 u012889234 的回复:] 比如有这样一个结构体   #define MAX_QUE_LEN 100  //定义数据包缓存队列 typedef struct _t_pkt_queue {     UINT4       V6_out_head;     UINT4       V6_out_tail;     UINT4       V6_out_curcnt;     tEthpkt *   V6_out_queue[MAX_QUE_LEN]; }tPktQue;  tEthpkt  *  是指向一个数据包的指针。 在父子进程间将其共享。在子进程中 (tEthpkt *)指针不为空，但是为什么不能对其进行操作？ Linux下在父进程用mmap创建匿名共享内存，共享内存的地址在父进程和子进程是一样的，父子进程都可以直接修改共享内存中的数据。 你说的子进程不能对其进行操作是什么意思？是取不到想要的数据还是修改了数据父进程看不见？ 你是怎么创建共享内存的？[/quote]    shmid = shmget(IPC_PRIVATE, sizeof(tPktQue), IPC_CREAT|0660);     if(shmid <= 0)     {         printf("\n***Create a shared memory Fail!\n");         return -1;     }     stacksize = getpagesize();     stack = malloc(stacksize);     if(stack == NULL)     {         printf("\n***Malloc For Child Process stack Failed!\n");         return -1;     }     childstack = stack + stacksize;     flags = CLONE_NEWPID|CLONE_NEWNS;     pid = clone(vdev_func, childstack, flags, (void *)shmid);     shmaddr = (char *)shmat(shmid, NULL, 0);     PktQue[i] = (tPktQue *)shmaddr;   //这里PktQue[i] 是一个指向tPktQue  的指针。   vdev_func子进程的调用函数。 在子进程中  shmaddr = (char *)shmat(shmid, NULL, 0); PktQue[i] = (tPktQue *)shmaddr;  比如对 PktQue[i] ->V6_out_queue[0]操作。操作不了。但其不为空。[/quote] 你都用clone了，可以不用shmget和shmat了。看一下我写的测试代码：  #define _GNU_SOURCE #include <sched.h>  #include <stdio.h> #include <stdlib.h> #include <unistd.h>  int data = 10; char *str = NULL;  int child_process(void *args) {     printf("Child process %d, data %d, str: %s\n", getpid(), data, str);     data = 20;     str = "child str";     printf("Child process %d, data %d, str: %s\n", getpid(), data, str);     while (1) {         sleep(1);     } }  int main(int argc, char *argv[]) {     void *stack = (void *)malloc(16384);     int clone_flag = CLONE_VM | CLONE_SIGHAND | CLONE_FS | CLONE_FILES;     str = "parent str";          clone(child_process, stack+16384, clone_flag, NULL);     printf("Parent process %d, data %d, str: %s\n", getpid(), data, str);     sleep(1);     while (1) {         sleep(1);     }      return 0; }  运行后输出： Child process 4517, data 10, str: parent str Child process 4517, data 20, str: child str Parent process 4516, data 20, str: child str

user: user-0
content: 我估计是 ： 只共享了指针，没有共享指针指向的内容。

user: user-0
content: 引用 2 楼 lovesmiles 的回复:fork出来的子进程已经拥有自己独立的进程空间，这个指针指向的是子进程的变量空间，对它的操作并不会影响到父进程的变量。  因为它们已经是指向两个不同的东西了。 没有用fork，目的是让他们操作同一块内存区域。

user: user-0
content: 引用 1 楼 wangzuxi 的回复:[quote=引用 楼主 u012889234 的回复:] 比如有这样一个结构体   #define MAX_QUE_LEN 100  //定义数据包缓存队列 typedef struct _t_pkt_queue {     UINT4       V6_out_head;     UINT4       V6_out_tail;     UINT4       V6_out_curcnt;     tEthpkt *   V6_out_queue[MAX_QUE_LEN]; }tPktQue;  tEthpkt  *  是指向一个数据包的指针。 在父子进程间将其共享。在子进程中 (tEthpkt *)指针不为空，但是为什么不能对其进行操作？ Linux下在父进程用mmap创建匿名共享内存，共享内存的地址在父进程和子进程是一样的，父子进程都可以直接修改共享内存中的数据。 你说的子进程不能对其进行操作是什么意思？是取不到想要的数据还是修改了数据父进程看不见？ 你是怎么创建共享内存的？[/quote]    shmid = shmget(IPC_PRIVATE, sizeof(tPktQue), IPC_CREAT|0660);     if(shmid <= 0)     {         printf("\n***Create a shared memory Fail!\n");         return -1;     }     stacksize = getpagesize();     stack = malloc(stacksize);     if(stack == NULL)     {         printf("\n***Malloc For Child Process stack Failed!\n");         return -1;     }     childstack = stack + stacksize;     flags = CLONE_NEWPID|CLONE_NEWNS;     pid = clone(vdev_func, childstack, flags, (void *)shmid);     shmaddr = (char *)shmat(shmid, NULL, 0);     PktQue[i] = (tPktQue *)shmaddr;   //这里PktQue[i] 是一个指向tPktQue  的指针。   vdev_func子进程的调用函数。 在子进程中  shmaddr = (char *)shmat(shmid, NULL, 0); PktQue[i] = (tPktQue *)shmaddr;  比如对 PktQue[i] ->V6_out_queue[0]操作。操作不了。但其不为空。

user: user-3
content: fork出来的子进程已经拥有自己独立的进程空间，这个指针指向的是子进程的变量空间，对它的操作并不会影响到父进程的变量。  因为它们已经是指向两个不同的东西了。

user: user-2
content: 引用 楼主 u012889234 的回复:比如有这样一个结构体   #define MAX_QUE_LEN 100  //定义数据包缓存队列 typedef struct _t_pkt_queue {     UINT4       V6_out_head;     UINT4       V6_out_tail;     UINT4       V6_out_curcnt;     tEthpkt *   V6_out_queue[MAX_QUE_LEN]; }tPktQue;  tEthpkt  *  是指向一个数据包的指针。 在父子进程间将其共享。在子进程中 (tEthpkt *)指针不为空，但是为什么不能对其进行操作？ Linux下在父进程用mmap创建匿名共享内存，共享内存的地址在父进程和子进程是一样的，父子进程都可以直接修改共享内存中的数据。 你说的子进程不能对其进行操作是什么意思？是取不到想要的数据还是修改了数据父进程看不见？ 你是怎么创建共享内存的？