时语-shine 2023-06-11 20:38 采纳率: 66.7%
浏览 67
已结题

实验——进程通信与共享内存

代码要求:

  1. 利用shmget()创建共享内存;
  2. 利用shmat()建立共享内存与进程之间的关联;
  3. 用fork()创建子进程,子进程与父进程共享存储空间;
  4. 利用信号量机制实现子进程读入数据到共享内存,父进程取出共享内存中的数据保存到文件,完成通信;
  5. 调用shmdt()断开共享内存连接;
  6. 调用shmctl()释放共享内存;
  7. 有注释,能在ubuntu上运行
  • 写回答

8条回答 默认 最新

  • Minuw 2023-06-11 20:59
    关注

    可参考

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <string.h>
    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/shm.h>
    #include <sys/sem.h>
    
    #define SHM_SIZE 1024
    
    // 定义共享内存结构体
    typedef struct {
        int flag;           // 标志位,0表示共享内存空闲,1表示共享内存已被写入数据
        char buf[SHM_SIZE]; // 数据缓冲区
    } shm_data_t;
    
    // 定义信号量结构体
    typedef union {
        int val;
        struct semid_ds *buf;
        unsigned short *array;
    } sem_union_t;
    
    // 定义信号量变量
    static int sem_id;
    
    // 定义P操作函数
    static int sem_p(int sem_id) {
        struct sembuf sem_op = {0, -1, SEM_UNDO};
        return semop(sem_id, &sem_op, 1);
    }
    
    // 定义V操作函数
    static int sem_v(int sem_id) {
        struct sembuf sem_op = {0, 1, SEM_UNDO};
        return semop(sem_id, &sem_op, 1);
    }
    
    int main() {
        int shmid;
        void *shmaddr;
        pid_t pid;
        shm_data_t *shm_data;
        sem_union_t sem_union;
    
        // 创建共享内存
        if ((shmid = shmget(IPC_PRIVATE, sizeof(shm_data_t), IPC_CREAT|0666)) < 0) {
            perror("shmget error");
            exit(1);
        }
    
        // 建立共享内存与进程之间的关联
        if ((shmaddr = shmat(shmid, NULL, 0)) == (void *)-1) {
            perror("shmat error");
            exit(1);
        }
    
        // 初始化共享内存
        shm_data = (shm_data_t *)shmaddr;
        shm_data->flag = 0;
    
        // 创建信号量
        if ((sem_id = semget(IPC_PRIVATE, 1, IPC_CREAT|0666)) < 0) {
            perror("semget error");
            exit(1);
        }
    
        // 初始化信号量
        sem_union.val = 1;
        if (semctl(sem_id, 0, SETVAL, sem_union) < 0) {
            perror("semctl error");
            exit(1);
        }
    
        // 创建子进程
        if ((pid = fork()) < 0) {
            perror("fork error");
            exit(1);
        } else if (pid == 0) { // 子进程
            int i = 0;
            char buf[SHM_SIZE];
    
            while (1) {
                sem_p(sem_id); // P操作
    
                // 如果共享内存空闲,写入数据
                if (shm_data->flag == 0) {
                    sprintf(buf, "This is data %d from child process.\n", ++i);
                    strncpy(shm_data->buf, buf, SHM_SIZE);
                    shm_data->flag = 1;
                }
    
                sem_v(sem_id); // V操作
    
                sleep(1); // 等待1秒钟
            }
        } else { // 父进程
            FILE *fp;
            char buf[SHM_SIZE];
    
            // 打开文件
            if ((fp = fopen("output.txt", "w")) == NULL) {
                perror("fopen error");
                exit(1);
            }
    
            while (1) {
                sem_p(sem_id); // P操作
    
                // 如果共享内存已被写入数据,从共享内存中读取数据并保存到文件中
                if (shm_data->flag == 1) {
                    strncpy(buf, shm_data->buf, SHM_SIZE);
                    fprintf(fp, "%s", buf);
                    shm_data->flag = 0;
                }
    
                sem_v(sem_id); // V操作
    
                sleep(1); // 等待1秒钟
            }
    
            // 关闭文件
            fclose(fp);
        }
    
        // 断开共享内存连接
        if (shmdt(shmaddr) < 0) {
            perror("shmdt error");
            exit(1);
        }
    
        // 释放共享内存
        if (shmctl(shmid, IPC_RMID, 0) < 0) {
            perror("shmctl error");
            exit(1);
        }
    
        // 释放信号量
        if (semctl(sem_id, 0, IPC_RMID, sem_union) < 0) {
            perror("semctl error");
            exit(1);
        }
    
        return 0;
    }
    
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论 编辑记录
查看更多回答(7条)

报告相同问题?

问题事件

  • 系统已结题 6月26日
  • 已采纳回答 6月18日
  • 创建了问题 6月11日