当前位置: 首页 > news >正文

[linux仓库]System V 进程通信详解:System V消息队列、信号量

🌟 各位看官好,我是

🌍 Linux == Linux is not Unix !

🚀 今天来学习Linux的消息队列以及信号量,从底层剖析内核如何管理IPC资源。

👍 如果觉得这篇文章有帮助,欢迎您一键三连,分享更多人哦!

目录

消息队列

​编辑

了解消息队列

信号量

理解信号量

信号量实操

PV操作 

 ​编辑 

总结

内核如何组织管理IPC资源

minishell添加管道实现


消息队列

通信的本质是什么?

让不同进程看到同一份资源啊!

根据前面所学这一份资源可以是基于文件的管道,在内存级申请一块资源,或者是一个被特殊处理的文件.它也可以是真真实实地在物理内存申请资源的共享内存,那么在内核里是否可以存在一串公共的队列结构里呢?这完全可以啊,我管道都能在内核中申请,这队OS来说也是easy的!

  • 消息队列提供了⼀个从⼀个进程向另外⼀个进程发送⼀块数据的方法
  • 每个数据块都被认为是有⼀个类型,接收者进程接收的数据块可以有不同的类型值
  • 特性方面 : IPC资源必须删除,否则不会自动清除,除⾮重启,所以system V IPC资源的⽣命周期随内核

既然可以在内核中申请消息队列,那么如果有多个进程创建多个消息队列,势必会有许多消息队列,哪些队列是刚创建的,哪些被销毁了,哪些是属于谁创建的。OS是否需要管理呢?要管理:

先描述 ! 再组织 !

了解消息队列

实际上消息队列与共享内存是非常类似的,只是接口需要熟悉下.为什么会这样呢?因为它们都是遵守System V 标准的哇!!!

但是消息队列不能像消息内存一样直接访问物理内存,而是需要通过系统调用

信号量

  • 多个执行流(进程), 能看到的同⼀份公共资源:共享资源

  • 被保护起来的资源叫做临界资源
  • 保护的⽅式常⻅:互斥与同步
  • 任何时刻,只允许⼀个执⾏流访问资源,叫做互斥
  • 多个执⾏流,访问临界资源的时候,具有⼀定的顺序性,叫做同步
  • 系统中某些资源⼀次只允许⼀个进程使⽤,称这样的资源为临界资源或互斥资源。
  • 在进程中涉及到互斥资源的程序段叫临界区(简单来说就是访问资源的那部分代码)。你写的代码=访问临界资源的代码(临界区)+不访问临界资源的代码(非临界区)

  • 所谓的对共享资源进行保护,本质是对访问共享资源的代码进行保护(如何保护呢? --> 写代码啊 --> 同步和互斥、加锁和解锁)

理解信号量

对资源的理解无过于两种:这份资源是作为资源整体被使用;亦或是这份资源被分成很多份,并不是作为整体使用.

为了进一步理解信号量,这里举两个例子: 

举个ATM机例子:

我们去银行卡取钱的时候,会限制一个门只能有一个人进行使用,其他人是不能看的.

举个看电影的例子:

对观影者:在看电影之前,我们必须要做什么 ? 买票 ! --> 那么买了这张票,这个座位是否就属于我们呢? --> 是属于的,只要买了票,座位这个资源就是我们的! --> 买票的本质:对资源的预定机制!

对经营者:电影院就那么多座位,我的这个票不能卖多啊;卖重复的票(不考虑) --> 那么该如何防止卖多票的情况呢? --> 用计数器啊! int count =100 ... 0.

那么什么是信号量呢?

信号量的本质:就是一把计数器 --> 描述临界资源数量多少的计数器.

保证:

  1. 资源不会出现多申请的情况
  2. 所有进程未来想通过临界区,访问临界资源 --> 先申请信号量(买票,完成对公共资源的一部分预定)

信号量本质:是一种描述临界资源数量的 原子性 的计数器,是对资源的 预定 机制

那么如果电影院就卖一张超级VIP票呢?刚好被一个富豪买走了.

此时其他人想进去,就只能等这个富豪看完电影,票又不为空才能买.等等,这不就是所谓的互斥机制吗?一次只允许一个人访问这份资源 --> 资源被作为整体使用.

 

信号量实操

semget():用于创建一个信号量集,返回信号量集的标识符。

int semget(key_t key, int nsems, int semflg);
  • key:信号量集的键,可以通过 ftok() 函数生成。
  • nsems:信号量集的大小,表示该信号量集包含的信号量个数。
  • semflg:操作标志,例如 IPC_CREAT 表示创建信号量集,0666 表示权限
  • 返回值是信号量集的标识符(semid)。

semctl():用于获取或设置信号量的控制信息,例如删除信号量等。

PV操作 

semop():用于执行 P 操作(wait)和 V 操作(signal)。

  

信号量是用来保护资源的(最典型的就是共享内存)

总结

所有的system V资源,生命周期都随内核!
所有的system V资源,都要被OS管理起来!

无论是共享内存、消息队列,还是信号量,都是遵守System V标准的.并且它们的结构体里都包含了一个共同的结构体:struct ipc_perm

为什么是这样子的呢?需要从内核剖析IPC资源. 

内核如何组织管理IPC资源

结论1:内核中管理IPC资源,用的是柔性数组管理!这是因为IPC资源不是固定的,会有变化,设计成柔性数组可以应对变化.

为什么要保存key?

结论2 : 可以通过ipc_ids的指针entries找到ipc_id_ary,ipc_id_ary里面含有kern ipc_perm指针类型的柔性数组,由于每一个数组下标都是指针类型,指向kern_ipc_perm结构体,这个结构体含有key。因此,通过遍历柔性数组指向结构体中的每一个key来确定是不是我们所需要的IPC资源.

那为什么又要有shmid这样的返回值呢?

结论3 : 遍历这个柔性数组的是O(n)时间复杂度,而shmid就是柔性数组的下标啊!可以直接定位这个资源在哪啊!

为什么共享内存要有file?

动态库是如何映射到我们的进程地址空间?

是如何找到动态库加载的起始地址?不过是多了个加载步骤

是如何做到加载时地址got重定向?

minishell添加管道实现

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#define MAX_CMD 1024
char command[MAX_CMD];int do_face()
{memset(command, 0x00, MAX_CMD);printf("minishell$ ");fflush(stdout);if (scanf("%[^\n]%*c", command) == 0){getchar();return -1;}return 0;
}char **do_parse(char *buff)
{int argc = 0;static char *argv[32];char *ptr = buff;while (*ptr != '\0'){if (!isspace(*ptr)){argv[argc++] = ptr;while ((!isspace(*ptr)) && (*ptr) != '\0'){ptr++;}continue;}*ptr = '\0';ptr++;}argv[argc] = NULL;return argv;
}int do_redirect(char *buff)
{char *ptr = buff, *file = NULL;int type = 0, fd, redirect_type = -1;while (*ptr != '\0'){if (*ptr == '>'){*ptr++ = '\0';redirect_type++;if (*ptr == '>'){*ptr++ = '\0';redirect_type++;}while (isspace(*ptr)){ptr++;}file = ptr;while ((!isspace(*ptr)) && *ptr != '\0'){ptr++;}*ptr = '\0';if (redirect_type == 0){fd = open(file, O_CREAT | O_TRUNC | O_WRONLY, 0664);}else{fd = open(file, O_CREAT | O_APPEND | O_WRONLY, 0664);}dup2(fd, 1);}ptr++;}return 0;
}int do_command(char *buff)
{int pipe_num = 0, i;char *ptr = buff;int pipefd[32][2] = {{-1}};int pid = -1;pipe_command[pipe_num] = ptr;while (*ptr != '\0'){if (*ptr == '|'){pipe_num++;*ptr++ = '\0';pipe_command[pipe_num] = ptr;continue;}ptr++;}pipe_command[pipe_num + 1] = NULL;return pipe_num;
}int do_pipe(int pipe_num)
{int pid = 0, i;int pipefd[10][2] = {{0}};char **argv = {NULL};for (i = 0; i <= pipe_num; i++){pipe(pipefd[i]);}for (i = 0; i <= pipe_num; i++){pid = fork();if (pid == 0){do_redirect(pipe_command[i]);argv = do_parse(pipe_command[i]);if (i != 0){close(pipefd[i][1]);dup2(pipefd[i][0], 0);}if (i != pipe_num){close(pipefd[i + 1][0]);dup2(pipefd[i + 1][1], 1);}execvp(argv[0], argv);}else{close(pipefd[i][0]);close(pipefd[i][1]);waitpid(pid, NULL, 0);}}return 0;
}int main(int argc, char *argv[])
{int num = 0;while (1){if (do_face() < 0)continue;num = do_command(command);do_pipe(num);}return 0;
}

http://www.dtcms.com/a/449817.html

相关文章:

  • css过渡属性
  • Linux系统--文件系统--动静态库
  • Spring进阶 - SpringMVC实现原理(二)DispatcherServlet处理请求的过程
  • SQL 面试高频:INNER JOIN vs LEFT JOIN 怎么考?
  • 【51单片机】【protues仿真】基于51单片机智能路灯控制系统
  • 3d模型免费素材网站wordpress如何修改行距
  • 再探类对象——C++入门进阶
  • 公司网站如何维护wordpress去掉title前空格及keywords最后的逗号
  • 仙居谁认识做网站的广告投放平台代理
  • 智慧餐厅管理系统qq群排名优化软件官网
  • InnoDB核心限制与应对策略
  • 贵州建设厅监理协会网站前后端分离实现网站开发
  • QNX 开发环境搭建
  • Java技术栈 —— 使用MinIO进行大文件分片上传与下载
  • `modprobe`命令 与 `KVM`模块 笔记251006
  • 山东省建设监理协会网站打不开赣州招聘网最新招聘
  • 贵阳网站建设设计个人网页设计作品集分析
  • 音乐介绍网站怎么做做暧暧小视频网站
  • 公网带宽1m能建设电商网站吗wordpress新建数据库
  • C57-断言函数assert
  • 网站的制作建站人汽车业务网站开发公司
  • 详解指针2
  • 第一章 :感知机(上)
  • 做网站都要会些什么设计网站建设合同书6
  • 网站开发工程师 能做什么响应式布局的概念
  • 反激开关电源
  • 长沙网站建设外贸0基础做电商从何下手
  • vs2015做网站做民宿需要和多家网站合作吗
  • 集团型网站建设室内设计平面图简单
  • 比利时网站后缀用php做的网站前后台模板