进程间通信方式(共享内存、信号灯集、消息队列)

2024-09-04 22:28

本文主要是介绍进程间通信方式(共享内存、信号灯集、消息队列),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

共享内存

特点

1)共享内存是一种最为高效的进程间通信方式,进程可以直接读写内存,而不需要任何数据的拷贝。

2)为了在多个进程间交换信息,内核专门留出了一块内存区,可以由需要访问的进程

将其映射到自己的私有地址空间。进程就可以直接读写这一内存区而不需要进行数据的拷贝,从而大大提高的效率。

3) 由于多个进程共享一段内存,因此也需要依靠某种同步机制,如互斥锁和信号量等

使用步骤

(1) 创建key值: ftok

(2) 创建或打开共享内存: shmget

(3) 映射共享内存到用户空间: shmat

(4) 撤销映射: shmdt

(5) 删除共享内存: shmctl

进程间通信:

命令

ipcs -m: 查看系统中的共享内存

ipcrm -m shmid:删除共享内存

ps: 可能不能直接删除掉还存在进程使用的共享内存,这时候可以用ps -ef对进程进行查看,kill掉多余的进程后,再使用ipcs查看。 

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

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

struct msg

{

int flag;

char buf[32];

};

头文件

typedef struct shared
{int flag;char buf[32];
} shared_t, *shared_p;

输入端

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <errno.h>
#include <string.h>
#include "shared.h"
int main(int argc, char const *argv[])
{key_t key;key = ftok("bus.c", 'a');if (key < 0){perror("key err");return -1;}printf("key:%#x\n", key);int shmid = shmget(key, sizeof(shared_t), IPC_CREAT | IPC_EXCL | 0777);if (shmid <= 0){if (errno == EEXIST){shmid = shmget(key, sizeof(shared_t), 0777);}else{perror("shmget err");return -1;}}printf("shmid:%d\n", shmid);shared_p p = (shared_p)shmat(shmid, NULL, 0);if (p == (shared_p)-1){perror("shmat err");return -1;}p->flag = 0;while (1){if (p->flag == 0){scanf("%s", p->buf);if (strcmp(p->buf, "quit") == 0)break;p->flag++;}}shmdt(p);shmctl(shmid, IPC_RMID, NULL);return 0;
}

输出端

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include "shared.h"
int main(int argc, char const *argv[])
{key_t key;key = ftok("bus.c", 'a');if (key < 0){perror("key err");return -1;}printf("key:%#x\n", key);int shmid = shmget(key, sizeof(shared_t), IPC_CREAT | IPC_EXCL | 0777);if (shmid <= 0){if (errno == EEXIST){shmid = shmget(key, sizeof(shared_t), 0777);}else{perror("shmget err");return -1;}}printf("shmid:%d\n", shmid);shared_p p = (shared_p)shmat(shmid, NULL, 0);if (p == (shared_p)-1){perror("shmat err");return -1;}while (1){sleep(1);if (strcmp(p->buf, "quit") == 0)exit(0);if (p->flag == 1){printf("%s\n", p->buf);p->flag--;}}shmdt(p);shmctl(shmid, IPC_RMID, NULL);return 0;
}

信号灯集

特点

信号灯(semaphore),也叫信号量,信号灯集是一个信号灯的集合。它是不同进程间或一个给定进程内部不同线程间同步的机制;

而Posix信号灯指的是单个计数信号灯:无名信号灯、有名信号灯。(咱们学的是无名信号灯)

System V的信号灯是一个或者多个信号灯的一个集合。其中的每一个都是单独的计数信号灯。

通过信号灯集实现共享内存的同步操作

使用步骤

(1) 创建键值:ftok

(2) 创建或打开信号灯集:semget

(3) 初始化信号灯:semctl

(4) pv操作:semop

(5) 删除信号灯集:semctl

命令

ipcs -s:查看信号灯集

ipcrm -s semid:删除信号灯集

注意:有时候可能会创建失败,或者semid为0,所以用命令看看,删了重新创建就可以了。

练习:两个进程实现通信,一个进程循环从终端输入,另一个进程循环打印,把信号灯集加到共享内存实现同步,输入输出quit结束

头文件

union semun
{int val;
};
key_t keyfun(char buf[32], char ch);
int shmcreate(key_t key);
int semcreate(key_t key, int num);
void seminit(int semid, int val, int num);
void sempv(int semid, int num, int op);

功能函数

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <errno.h>
#include <string.h>
#include "sem.h"key_t keyfun(char buf[32], char ch)
{key_t key;key = ftok(buf, ch);if (key < 0){perror("ftok err");return -1;}printf("key:%#x\n", key);return key;
}int shmcreate(key_t key)
{int shmid = shmget(key, sizeof(str), IPC_CREAT | IPC_EXCL | 0777);if (shmid <= 0){if (errno == EEXIST)shmid = shmget(key, sizeof(str), 0777);else{perror("shmget err");return -1;}}printf("shmid: %d\n", shmid);return shmid;
}int semcreate(key_t key, int num)
{int semid = semget(key, num, IPC_CREAT | IPC_EXCL | 0777);if (semid <= 0){if (errno == EEXIST){semid = semget(key, num, 0777);}else{perror("semget err");return -1;}}else{seminit(semid, 0, 0);seminit(semid, 1, 1);}printf("semid:%d\n", semid);return semid;
}void seminit(int semid, int num, int val)
{union semun mysem;mysem.val = val;semctl(semid, num, SETVAL, mysem);
}void sempv(int semid, int num, int op)
{struct sembuf buf; // sembuf结构体人家写好的直接拿来用就可以// PV操作buf.sem_num = num;buf.sem_op = op;buf.sem_flg = 0;       // 阻塞semop(semid, &buf, 1); // 对num号灯进行op操作申请资源
}

输入端

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <errno.h>
#include <string.h>
#include "sem.h"
int main(int argc, char const *argv[])
{key_t key = keyfun("sem.h", 'a');int semid = semcreate(key, 2);int shmid = shmcreate(key);// 映射共享内存char *p = (char *)shmat(shmid, NULL, 0);if (p == (char *)-1){perror("shmat err");return -1;}while (1){sempv(semid, 1, -1);scanf("%s", p);sempv(semid, 0, 1);if (strcmp(p, "quit") == 0)break;}printf("0:%d\n", semctl(semid, 0, GETVAL));printf("1:%d\n", semctl(semid, 1, GETVAL));shmdt(p);// semctl(semid, 0, IPC_RMID);return 0;
}

输出端

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <errno.h>
#include <string.h>
#include "sem.h"
int main(int argc, char const *argv[])
{key_t key = keyfun("sem.h", 'a');int semid = semcreate(key, 2);int shmid = shmcreate(key);// 映射共享内存char *p = (char *)shmat(shmid, NULL, 0);if (p == (char *)-1){perror("shmat err");return -1;}while (1){sempv(semid, 0, -1);if (strcmp(p, "quit") == 0)break;printf("%s\n", p);sempv(semid, 1, 1);}printf("0:%d\n", semctl(semid, 0, GETVAL));printf("1:%d\n", semctl(semid, 1, GETVAL));shmdt(p);// semctl(semid, 0, IPC_RMID);return 0;
}

消息队列

特点

消息队列是IPC对象(活动在内核级别的一种进程间通信的工具)的一种

一个消息队列由一个标识符 (即队列ID)来标识

消息队列就是一个消息的列表。用户可以在消息队列中添加消息、读取消息等

消息队列可以按照类型(自己设一个值作为类型)来发送/接收消息

使用步骤

(1) 创建key值:ftok

(2) 创建或打开消息队列:msgget

(3) 添加消息:按照消息的类型把消息添加到已经打开的消息队列末尾msgsnd

(4) 读取消息:可以按照消息类型把消息从消息队列中取走msgrcv

(5) 删除消息队列:msgctl

命令

ipcs -q:查看消息队列

ipcrm -q msgid:删除消息队列

这篇关于进程间通信方式(共享内存、信号灯集、消息队列)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1137201

相关文章

hdu1180(广搜+优先队列)

此题要求最少到达目标点T的最短时间,所以我选择了广度优先搜索,并且要用到优先队列。 另外此题注意点较多,比如说可以在某个点停留,我wa了好多两次,就是因为忽略了这一点,然后参考了大神的思想,然后经过反复修改才AC的 这是我的代码 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<

内核启动时减少log的方式

内核引导选项 内核引导选项大体上可以分为两类:一类与设备无关、另一类与设备有关。与设备有关的引导选项多如牛毛,需要你自己阅读内核中的相应驱动程序源码以获取其能够接受的引导选项。比如,如果你想知道可以向 AHA1542 SCSI 驱动程序传递哪些引导选项,那么就查看 drivers/scsi/aha1542.c 文件,一般在前面 100 行注释里就可以找到所接受的引导选项说明。大多数选项是通过"_

用命令行的方式启动.netcore webapi

用命令行的方式启动.netcore web项目 进入指定的项目文件夹,比如我发布后的代码放在下面文件夹中 在此地址栏中输入“cmd”,打开命令提示符,进入到发布代码目录 命令行启动.netcore项目的命令为:  dotnet 项目启动文件.dll --urls="http://*:对外端口" --ip="本机ip" --port=项目内部端口 例: dotnet Imagine.M

poj 3190 优先队列+贪心

题意: 有n头牛,分别给他们挤奶的时间。 然后每头牛挤奶的时候都要在一个stall里面,并且每个stall每次只能占用一头牛。 问最少需要多少个stall,并输出每头牛所在的stall。 e.g 样例: INPUT: 51 102 43 65 84 7 OUTPUT: 412324 HINT: Explanation of the s

poj 2431 poj 3253 优先队列的运用

poj 2431: 题意: 一条路起点为0, 终点为l。 卡车初始时在0点,并且有p升油,假设油箱无限大。 给n个加油站,每个加油站距离终点 l 距离为 x[i],可以加的油量为fuel[i]。 问最少加几次油可以到达终点,若不能到达,输出-1。 解析: 《挑战程序设计竞赛》: “在卡车开往终点的途中,只有在加油站才可以加油。但是,如果认为“在到达加油站i时,就获得了一

[Linux]:进程(下)

✨✨ 欢迎大家来到贝蒂大讲堂✨✨ 🎈🎈养成好习惯,先赞后看哦~🎈🎈 所属专栏:Linux学习 贝蒂的主页:Betty’s blog 1. 进程终止 1.1 进程退出的场景 进程退出只有以下三种情况: 代码运行完毕,结果正确。代码运行完毕,结果不正确。代码异常终止(进程崩溃)。 1.2 进程退出码 在编程中,我们通常认为main函数是代码的入口,但实际上它只是用户级

深入理解RxJava:响应式编程的现代方式

在当今的软件开发世界中,异步编程和事件驱动的架构变得越来越重要。RxJava,作为响应式编程(Reactive Programming)的一个流行库,为Java和Android开发者提供了一种强大的方式来处理异步任务和事件流。本文将深入探讨RxJava的核心概念、优势以及如何在实际项目中应用它。 文章目录 💯 什么是RxJava?💯 响应式编程的优势💯 RxJava的核心概念

poj3750约瑟夫环,循环队列

Description 有N个小孩围成一圈,给他们从1开始依次编号,现指定从第W个开始报数,报到第S个时,该小孩出列,然后从下一个小孩开始报数,仍是报到S个出列,如此重复下去,直到所有的小孩都出列(总人数不足S个时将循环报数),求小孩出列的顺序。 Input 第一行输入小孩的人数N(N<=64) 接下来每行输入一个小孩的名字(人名不超过15个字符) 最后一行输入W,S (W < N),用

【即时通讯】轮询方式实现

技术栈 LayUI、jQuery实现前端效果。django4.2、django-ninja实现后端接口。 代码仓 - 后端 代码仓 - 前端 实现功能 首次访问页面并发送消息时需要设置昵称发送内容为空时要提示用户不能发送空消息前端定时获取消息,然后展示在页面上。 效果展示 首次发送需要设置昵称 发送消息与消息展示 提示用户不能发送空消息 后端接口 发送消息 DB = []@ro

POJ2010 贪心优先队列

c头牛,需要选n头(奇数);学校总共有f的资金, 每头牛分数score和学费cost,问合法招生方案中,中间分数(即排名第(n+1)/2)最高的是多少。 n头牛按照先score后cost从小到大排序; 枚举中间score的牛,  预处理左边与右边的最小花费和。 预处理直接优先队列贪心 public class Main {public static voi