【问题标题】:How do I print stored data from the shared memory?如何打印共享内存中存储的数据?
【发布时间】:2024-01-15 03:58:01
【问题描述】:

我有以下程序:

#include <stdio.h>
#include <sys/types.h>
#define MAX_COUNT 100

void ChildProcess(void);
void ParentProcess(void);

void main(void)
{
    pid_t pid;
    pid = fork();
    
    if (pid == 0)
        ChildProcess();
     else
        ParentProcess();
}

void ChildProcess(void)
{
    int i;
    for (i = 1; i <= MAX_COUNT; i++)
        printf(" This line is from child, value = %d\n", i);
    printf(" *** Child process is done ***\n");
}

void ParentProcess(void)
{
    int i;
    for (i = 1; i <= MAX_COUNT; i++)
        printf("This line is from parent, value = %d\n", i);
    printf("*** Parent is done ***\n");
}

我必须修改它,让父子打印共享内存中存储的数据,方式如下:

  • 在父级中创建并初始化共享内存。
  • 用 5 个整数填充共享内存。 (我应该分配足够的共享内存来存储 5 个整数。)
  • 从父级分叉到子级。
  • 如果 fork 成功,则子进程必须打印存储在共享内存中的值,如预期输出所示,其中 N1、N2、N3、N4、N5 是在共享内存中找到的数字。

Expected output

我在 ParentProcess 函数中所做的如下:

void ParentProcess(void)
{
    int i;
    
    for (i = 1; i <= MAX_COUNT; i++)
        printf("This line is from parent, value = %d\n", i);
    printf("*** Parent is done ***\n");
    
    int localVar = 0;
    int* p = (int*) malloc(2);
    pid_t childPID = fork();
    *p = 0;
    
    if (childPID >= 0)
    {
        printf("\nChild process has started\n");
        if (childPID == 0)
        {
            localVar++;
            globalVar++;
            printf("Child process has found the following data %d,", *p);
            *p = 70;
            printf( " %d,", *p); 
            *p = 66; 
            printf(" %d,", *p); 
            *p = 51; 
            printf(" %d,", *p); 
            *p = 90; 
            printf(" %d in shared memory\n",*p); 
            
            printf("Child is existing\n\n");
        } 
    } 
   
}

现在我意识到我做错了,但我不知道如何解决这个问题。我想我必须使用shmget 来创建共享内存,但是然后呢?如何在其中存储值?

如果您发现无法帮助我解决此问题或时间过长,请分享资源,我可以在其中了解更多关于 Linux 中的 C 编程,特别是关于共享内存的使用。提前谢谢你

【问题讨论】:

    标签: c linux fork shared-memory


    【解决方案1】:

    最好先弄清楚你想做什么,因为据我阅读你的代码,你在代码中调用了两次 fork()(一次在 main() 函数中,一次在 ParentProcess() 函数中)

    所以我为父/子共享内存编写了通用解决方案。有几种方法可以实现共享内存,但这是一个示例,它是此处代码的修改版本 How to use shared memory with Linux in C

    #include <string.h>
    #include <unistd.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/mman.h>
    #include <sys/wait.h>
    
    void *create_shared_memory(size_t size)
    {
        int protection = PROT_READ | PROT_WRITE;
        int visibility = MAP_SHARED | MAP_ANONYMOUS;
        return mmap(NULL, size, protection, visibility, -1, 0);
    }
    
    int main()
    {
        // Allocate 4 ints
        void *shmem = create_shared_memory(sizeof(int)*4);
    
        if( shmem == NULL ){
            fprintf(stderr, "Failed to create shared memory\n");
            return -1;
        }
    
        // Initialize 4 ints
        ((int*)shmem)[0] = 10;
        ((int*)shmem)[1] = 100;
        ((int*)shmem)[2] = 1000;
        ((int*)shmem)[3] = 10000;
    
        int pid = fork();
    
        if (pid == 0)
        {
            // Print 4 ints in child
            printf("Child reading int 0: %d\n", ((int*)shmem)[0]);
            printf("Child reading int 1: %d\n", ((int*)shmem)[1]);
            printf("Child reading int 2: %d\n", ((int*)shmem)[2]);
            printf("Child reading int 3: %d\n", ((int*)shmem)[3]);
            printf("Child end\n");
        }
        else
        {
            printf("Parent waiting for child ends...\n");
            waitpid(pid, NULL, 0);
            printf("Parent ends\n");
        }
    
        int ret = munmap(shmem, sizeof(int)*4);
        if( ret != 0 ){
            fprintf(stderr, "Failed to unmap shared memory\n");
            return -1;
        }
    
        return 0;
    }
    

    【讨论】:

      【解决方案2】:

      我编写了一小段 c 代码,您可能会觉得有帮助:

      #include <stdlib.h>
      #include <stdio.h>
      #include <unistd.h>
      #include <errno.h>
      #include <sys/ipc.h>
      #include <sys/shm.h>
      #include <sys/sem.h>
      
      #define NUM_INTS    5
      
      int main(int argc, char *argv[])
      {
          key_t key = (key_t) 123456;
          int shmgetrc, semgetrc;
          struct shmid_ds ds;
          int *shared_values;
          int i;
          struct sembuf sops[2];
          int semid;
      
          sops[0].sem_num = 0;        /* Operate on semaphore 0 */
          sops[0].sem_op = 0;         /* Wait for value to equal 0 */
          sops[0].sem_flg = 0;
      
          sops[1].sem_num = 0;        /* Operate on semaphore 0 */
          sops[1].sem_op = 1;         /* Increment value by one */
          sops[1].sem_flg = 0;
      
      
          /* create SHM segment */
          shmgetrc = shmget(key, NUM_INTS * sizeof(int), IPC_CREAT | IPC_EXCL | 0x180);
          if (shmgetrc < 0) {
              perror("shmget failed...");
              exit(1);
          }
          /* retrieve the address of the segment */
          shared_values = (int *) shmat(shmgetrc, NULL, 0);
      
          /* create a semaphore */
          semgetrc = semget(key, 1, IPC_CREAT | IPC_EXCL | 0x180);
          if (semgetrc < 0) {
              perror("semget failed...");
              exit(1);
          }
      
          /* lock the semaphore */
          if (semop(semgetrc, sops, 2) == -1) {
              perror("semop lock failed ...");
              exit(1);
          }
      
          /* fill it with values */
          for (i = 0; i < NUM_INTS; ++i) {
              shared_values[i] = i;
          }
      
          /* unlock the semaphore */
          sops[0].sem_op = -1;
          if (semop(semgetrc, sops, 1) == -1) {
              perror("semop release failed ...");
              exit(1);
          }
      
          /* here something else could happen */
          sleep(60);
      
          /* lock the semaphore */
          sops[0].sem_op = 0;
          if (semop(semgetrc, sops, 2) == -1) {
              perror("semop lock failed ...");
              exit(1);
          }
      
          /* print values */
          for (i = 0; i < NUM_INTS; ++i) {
              printf("%d ", shared_values[i]);
          }
          printf("\n");
      
          /* unlock the semaphore */
          sops[0].sem_op = -1;
          if (semop(semgetrc, sops, 1) == -1) {
              perror("semop release failed ...");
              exit(1);
          }
      
          /* remove the semaphore */
          if (semctl(semgetrc, semgetrc, IPC_RMID) < 0) {
              perror("semctl failed ...");
              exit(1);
          }
      
          /* remove shm segment again */
          if (shmctl(shmgetrc, IPC_RMID, &ds) < 0) {
              perror("shmctl failed ...");
              exit(1);
          }
          exit(0);
      }
      

      我并没有打算写出有史以来最漂亮的代码,只是一个例子表明:

      • 如何创建 shm 段
      • 如何检索和使用地址
      • 如何删除它

      此外,我使用信号量来保护访问。

      与其他答案相反,我使用的是 ipc 接口,而不是 mmap()。

      【讨论】: