目录
题目
两个进程实现通信,一个进程循环从终端输入,另一个进程循环打印,当输入quit时结束这两个标志在两个进程里,是不共享的,所以为了共享标志位可以和buf封装到一个结构体里作为共享内存。
struct msg
{
int flag;
char buf[32];
};
思路
一、整体功能概述
这段代码通过共享内存实现了两个进程之间的通信。一个进程负责从终端接收输入,另一个进程负责循环打印输入的内容,当输入为 “quit” 时,两个进程都结束。
二、结构体定义与共享内存的作用
- 定义了一个结构体
struct msg
,包含一个标志位flag
和一个字符数组buf[32]
。这个结构体将用于存储输入的字符串和一个标志,以协调两个进程的操作。- 通过共享内存,两个进程可以访问同一块内存区域,即这个结构体。这样就实现了在不同进程之间共享数据的目的。
三、
input
进程分析
生成共享内存键值:
- 使用
ftok
函数以指定的文件("shm.c")和字符('a')生成一个唯一的键值key
。如果生成键值失败,输出错误信息并返回-1
。创建或打开共享内存:
- 使用
shmget
函数尝试创建一个新的共享内存段。如果共享内存已经存在(errno == EEXIST
),则打开已有的共享内存。如果创建或打开共享内存失败,输出错误信息并返回-1
。映射共享内存:
- 使用
shmat
函数将共享内存映射到进程的地址空间。如果映射失败,输出错误信息并返回-1
。输入循环:
- 在一个无限循环中,当标志位
flag
为 0 时,从终端读取输入并存储到buf
中,然后将标志位设置为 1。- 如果输入的字符串是 “quit”,则退出循环。
取消映射和删除共享内存(可选):
- 使用
shmdt
函数取消共享内存的映射。- 可以选择使用
shmctl
函数删除共享内存,但在代码中被注释掉了。四、
output
进程分析
与
input
进程类似的步骤生成键值、创建或打开共享内存以及映射共享内存。输出循环:
- 在一个无限循环中,检查输入的字符串是否为 “quit”,如果是则退出循环。
- 当标志位
flag
为 1 时,打印存储在buf
中的字符串,然后将标志位设置为 0。与
input
进程类似的取消映射和删除共享内存(可选)步骤。五、总体执行流程分析
- 分别运行
input
和output
两个程序,它们会生成相同的键值,从而可以访问同一块共享内存。input
进程等待用户输入,并将输入存储在共享内存中,设置标志位表示有新的输入。output
进程不断检查共享内存中的标志位和输入内容,如果有新的输入则打印出来,并重置标志位。- 当
input
进程输入 “quit” 时,两个进程都会检测到这个字符串并退出循环,然后可以选择删除共享内存以释放系统资源。六、应用场景和注意事项
应用场景:
- 适用于需要在不同进程之间进行数据交互的场景,尤其是当数据量较大或者需要频繁通信时,共享内存可以提供高效的通信方式。
- 可以用于实现分布式系统中的数据共享和协调。
注意事项:
- 确保在使用共享内存时进行适当的同步和互斥操作,以避免数据竞争和不一致性。这里的标志位可以起到一定的同步作用,但在更复杂的场景中可能需要使用信号量等同步机制。
- 注意在程序结束时正确地取消映射和删除共享内存,以避免资源泄漏。
- 考虑共享内存的大小限制,避免存储过多的数据导致内存溢出。
实现:
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;
}
标签:include,flag,循环,key,进程,共享内存,buf,输入
From: https://blog.csdn.net/QR70892/article/details/141906378