【问题标题】:How to share memory between processes created by fork()?如何在 fork() 创建的进程之间共享内存?
【发布时间】:2021-12-02 03:14:34
【问题描述】:

在fork child中,如果我们修改了一个全局变量,它不会在主程序中改变。

有没有办法改变子叉子中的全局变量?

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int glob_var;

main (int ac, char **av)
{
  int pid;

  glob_var = 1;

  if ((pid = fork()) == 0) {
    /* child */
    glob_var = 5;
  }
  else {
    /* Error */
    perror ("fork");
    exit (1);
  }

  int status;
  while (wait(&status) != pid) {
  }
   printf("%d\n",glob_var); // this will display 1 and not 5.
}

【问题讨论】:

标签: c fork


【解决方案1】:

您可以使用共享内存(shm_open()shm_unlink()mmap() 等)。

#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

static int *glob_var;

int main(void)
{
    glob_var = mmap(NULL, sizeof *glob_var, PROT_READ | PROT_WRITE, 
                    MAP_SHARED | MAP_ANONYMOUS, -1, 0);

    *glob_var = 1;

    if (fork() == 0) {
        *glob_var = 5;
        exit(EXIT_SUCCESS);
    } else {
        wait(NULL);
        printf("%d\n", *glob_var);
        munmap(glob_var, sizeof *glob_var);
    }
    return 0;
}

【讨论】:

  • 你能提供一个简单的例子吗
  • 你需要查找共享内存; google 上有很多例子。这允许两个独立的应用程序使用相同的内存来存储和读取变量。当您fork() 一个进程时,它会创建一个子进程,该子进程具有与父进程不同的内存堆。您的父级将维护其全局变量,而子级将分配自己的副本。
  • 你可以找到一些解释很好的例子here
  • @md5:在 mmap 函数调用中,文件描述符句柄为“-1”。 -1 表示什么?
  • @TheLoneJoker。来自mmap:however, some implementations require fd to be -1 if MAP_ANONYMOUS (or MAP_ANON) is specified, and portable applications should ensure this的手册页
【解决方案2】:

无法更改全局变量,因为新创建的进程(子进程)拥有自己的地址空间。

所以最好使用shmget(),shmat() from POSIX api

或者您可以使用 pthread ,因为 pthreads 共享 globaldata 并且全局变量的更改会反映在父级中。

然后阅读一些Pthreads tutorial

【讨论】:

    【解决方案3】:

    这是一个替代解决方案。

    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/shm.h>
    #include <sys/stat.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <sys/wait.h>
    
    typedef struct
    {
      int id;
      size_t size;
    } shm_t;
    
    shm_t *shm_new(size_t size)
    {
      shm_t *shm = calloc(1, sizeof *shm);
      shm->size = size;
    
      if ((shm->id = shmget(IPC_PRIVATE, size, IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR)) < 0)
      {
        perror("shmget");
        free(shm);
        return NULL;
      }
    
      return shm;
    }
    
    void shm_write(shm_t *shm, void *data)
    {
      void *shm_data;
    
      if ((shm_data = shmat(shm->id, NULL, 0)) == (void *) -1)
      {
        perror("write");
        return;
      }
    
      memcpy(shm_data, data, shm->size);
      shmdt(shm_data);
    }
    
    void shm_read(void *data, shm_t *shm)
    {
      void *shm_data;
    
      if ((shm_data = shmat(shm->id, NULL, 0)) == (void *) -1)
      {
        perror("read");
        return;
      }
      memcpy(data, shm_data, shm->size);
      shmdt(shm_data);
    }
    
    void shm_del(shm_t *shm)
    {
      shmctl(shm->id, IPC_RMID, 0);
      free(shm);
    }
    
    int main()
    {
      int var = 1;
      shm_t *shm = shm_new(sizeof var);
    
      int pid;
      if ((pid = fork()) == 0)
      { /* child */
        var = 5;
        shm_write(shm, &var);
        printf("child: %d\n", var);
        return 0;
      }
      /* Wait for child to return */
      int status;
      while (wait(&status) != pid);
      /* */
      shm_read(&var, shm);
      /* Parent is updated by child */
      printf("parent: %d\n", var);
      shm_del(shm);
      return 0;
    }
    

    构建:

    $ gcc shm.c -o shm && ./shm
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-07-16
      • 1970-01-01
      • 2012-07-03
      • 2012-01-11
      • 1970-01-01
      相关资源
      最近更新 更多