两个进程实现通信,一个进程循环从终端输入,另一个进程循环打印,当输入quit时结束

目录

题目

思路

实现:

input.c

output.c


题目

两个进程实现通信,一个进程循环从终端输入,另一个进程循环打印,当输入quit时结束

这两个标志在两个进程里,是不共享的,所以为了共享标志位可以和buf封装到一个结构体里作为共享内存。

struct msg

{

int flag;

char buf[32];

};

思路

一、整体功能概述

 

这段代码通过共享内存实现了两个进程之间的通信。一个进程负责从终端接收输入,另一个进程负责循环打印输入的内容,当输入为 “quit” 时,两个进程都结束。

 

二、结构体定义与共享内存的作用

 
  1. 定义了一个结构体 struct msg,包含一个标志位 flag 和一个字符数组 buf[32]。这个结构体将用于存储输入的字符串和一个标志,以协调两个进程的操作。
  2. 通过共享内存,两个进程可以访问同一块内存区域,即这个结构体。这样就实现了在不同进程之间共享数据的目的。
 

三、input 进程分析

 
  1. 生成共享内存键值

    • 使用 ftok 函数以指定的文件("shm.c")和字符('a')生成一个唯一的键值 key。如果生成键值失败,输出错误信息并返回 -1
  2. 创建或打开共享内存

    • 使用 shmget 函数尝试创建一个新的共享内存段。如果共享内存已经存在(errno == EEXIST),则打开已有的共享内存。如果创建或打开共享内存失败,输出错误信息并返回 -1
  3. 映射共享内存

    • 使用 shmat 函数将共享内存映射到进程的地址空间。如果映射失败,输出错误信息并返回 -1
  4. 输入循环

    • 在一个无限循环中,当标志位 flag 为 0 时,从终端读取输入并存储到 buf 中,然后将标志位设置为 1。
    • 如果输入的字符串是 “quit”,则退出循环。
  5. 取消映射和删除共享内存(可选)

    • 使用 shmdt 函数取消共享内存的映射。
    • 可以选择使用 shmctl 函数删除共享内存,但在代码中被注释掉了。
 

四、output 进程分析

 
  1. 与 input 进程类似的步骤生成键值、创建或打开共享内存以及映射共享内存。

  2. 输出循环

    • 在一个无限循环中,检查输入的字符串是否为 “quit”,如果是则退出循环。
    • 当标志位 flag 为 1 时,打印存储在 buf 中的字符串,然后将标志位设置为 0。
  3. 与 input 进程类似的取消映射和删除共享内存(可选)步骤。

 

五、总体执行流程分析

 
  1. 分别运行 input 和 output 两个程序,它们会生成相同的键值,从而可以访问同一块共享内存。
  2. input 进程等待用户输入,并将输入存储在共享内存中,设置标志位表示有新的输入。
  3. output 进程不断检查共享内存中的标志位和输入内容,如果有新的输入则打印出来,并重置标志位。
  4. 当 input 进程输入 “quit” 时,两个进程都会检测到这个字符串并退出循环,然后可以选择删除共享内存以释放系统资源。
 

六、应用场景和注意事项

 
  1. 应用场景:

    • 适用于需要在不同进程之间进行数据交互的场景,尤其是当数据量较大或者需要频繁通信时,共享内存可以提供高效的通信方式。
    • 可以用于实现分布式系统中的数据共享和协调。
  2. 注意事项:

    • 确保在使用共享内存时进行适当的同步和互斥操作,以避免数据竞争和不一致性。这里的标志位可以起到一定的同步作用,但在更复杂的场景中可能需要使用信号量等同步机制。
    • 注意在程序结束时正确地取消映射和删除共享内存,以避免资源泄漏。
    • 考虑共享内存的大小限制,避免存储过多的数据导致内存溢出。

实现:

input.c

#include <sys/types.h>
#include <sys/ipc.h>
#include <stdio.h>
#include <sys/shm.h>
#include <errno.h>
#include <string.h>

struct msg
{
    int flag;
    char buf[32];
};

int main(int argc, char const *argv[])
{
    int shmid;
    key_t key;
    struct msg *p;
    key = ftok("shm.c", 'a');
    if (key < 0)
    {
        perror("key err");
        return -1;
    }
    printf("key: %#x\n", key);

    //打开或创建共享内存
    shmid = shmget(key, sizeof(struct msg), IPC_CREAT | IPC_EXCL | 0777); //如果共享内存不存在则创建,存在则返回-1
    if (shmid <= 0)
    {
        if (errno == EEXIST)                               //如果共享内存已存在则,直接打开
            shmid = shmget(key, sizeof(struct msg), 0777); //直接打开已有的共享内存并且获得共享内存id
        else
        {
            perror("shmget err");
            return -1;
        }
    }
    printf("shmid: %d\n", shmid);

    //映射共享内存
    p = (struct msg *)shmat(shmid, NULL, 0);
    if (p == (struct msg *)-1)
    {
        perror("shmat err");
        return -1;
    }

    p->flag = 0;
    while (1)
    {
        if (strcmp(p->buf, "quit") == 0)
            break;
        if (p->flag == 1)
        {
            printf("%s\n", p->buf);
            p->flag = 0;
        }
    }

    //取消映射
    shmdt(p);

    //删除共享内存
    //shmctl(shmid,IPC_RMID,NULL);

    return 0;
}

output.c

#include <sys/types.h>
#include <sys/ipc.h>
#include <stdio.h>
#include <sys/shm.h>
#include <errno.h>
#include <string.h>

struct msg
{
    int flag;
    char buf[32];
};

int main(int argc, char const *argv[])
{
    int shmid;
    key_t key;
    struct msg *p;
    key = ftok("shm.c", 'a');
    if (key < 0)
    {
        perror("key err");
        return -1;
    }
    printf("key: %#x\n", key);

    //打开或创建共享内存
    shmid = shmget(key, sizeof(struct msg), IPC_CREAT | IPC_EXCL | 0777); //如果共享内存不存在则创建,存在则返回-1
    if (shmid <= 0)
    {
        if (errno == EEXIST)                               //如果共享内存已存在则,直接打开
            shmid = shmget(key, sizeof(struct msg), 0777); //直接打开已有的共享内存并且获得共享内存id
        else
        {
            perror("shmget err");
            return -1;
        }
    }
    printf("shmid: %d\n", shmid);

    //映射共享内存
    p = (struct msg *)shmat(shmid, NULL, 0);
    if (p == (struct msg *)-1)
    {
        perror("shmat err");
        return -1;
    }

    p->flag = 0;
    while (1)
    {
        if (strcmp(p->buf, "quit") == 0)
            break;
        if (p->flag == 1)
        {
            printf("%s\n", p->buf);
            p->flag = 0;
        }
    }

    //取消映射
    shmdt(p);

    //删除共享内存
    //shmctl(shmid,IPC_RMID,NULL);

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值