Linux 第二十七章

🐶博主主页:@ᰔᩚ. 一怀明月ꦿ 

❤️‍🔥专栏系列:线性代数,C初学者入门训练,题解C,C的使用文章,「初学」C++,linux

🔥座右铭:“不要等到什么都没有了,才下定决心去做”

🚀🚀🚀大家觉不错的话,就恳求大家点点关注,点点小爱心,指点指点🚀🚀🚀

目录

可执行程序加载的时候,动态库也需要加载

符号表

在磁盘中,习惯叫逻辑地址:起始地址+偏移量

进程间通信 

进程间通信的目的

进程间通信的本质

匿名管道通信

pipe()

进程池

to_string

function()>

匿名管道的实现

processpool.cc

task.hpp

Makefile


可执行程序加载的时候,动态库也需要加载

动态库加载的时候,会从磁盘写入内存,然后通过页表映射到进程虚拟地址空间中的共享区中

我们要做到让库在共享区的任意位置,都可以正确运行

符号表

在 Linux 中,符号表是一个记录了程序中各个函数、变量以及其他符号的名称和地址映射关系的数据结构。在编译程序时,编译器会生成符号表并将其嵌入到可执行文件中。当程序运行时,操作系统会将符号表加载到内存中,并使用它来解析程序中的符号引用

如果一个程序运行时已经加载了一个动态库 libxxx.so,然后另一个程序运行时,该程序也需使用动态库libxxx.so,那么该程序还需要加载动态库 libxxx.so吗?

不需要。因为我们动态库 libxxx.so已经加载到内存中,我们只需要使用该进程的虚拟地址空间去映射内存中的已经加载的动态库 libxxx.so

所以不管多少个进程使用同一个动态库,内存中只需要一份动态库

在磁盘中,习惯叫逻辑地址:起始地址+偏移量

当一个程序被执行时,它的可执行文件(通常是 ELF 格式)会被加载到内存中的代码段(text segment)。这个可执行文件可能会引用一些静态库,这些静态库也会被加载到内存中。

静态库是在编译时将库的代码和数据包含在可执行文件中的。当程序加载到内存时,操作系统会将静态库的内容复制到进程的地址空间中,使程序能够访问静态库中的函数和数据。这样,程序就可以直接调用静态库中定义的函数,而不需要在运行时再去查找和加载动态库。

当一个程序被执行时,它的可执行文件(通常是 ELF 格式)会被加载到内存中的代码段(text segment)。这个可执行文件可能会依赖一些动态库,这些动态库也需要被加载到内存中。

动态库是以共享对象(Shared Object)的形式存在的,它们的代码和数据并不包含在可执行文件中,而是作为独立的文件存在。当程序加载到内存时,操作系统会根据可执行文件中的信息找到并加载所依赖的动态库。加载动态库的过程包括将动态库的代码和数据复制到进程的地址空间中,并进行符号重定位等操作,使得程序能够正确地使用动态库中的函数和数据。

cpu中的指令寄存器,可以通过虚拟地址,然后通过页表,找到物理地址,然后找到内存里的命令

进程间通信 

vscode的使用

1)下载vscode

2)然后下载中文插件

3)下载ssh remote插件(用于远程连接)

control+`:就是打开终端和在final shell操作一样

主要是用vscode取代vim,但是vim还是有用的,我们是远程开发,我安装的插件安装到linux下

进程间通信的目的

数据传输:一个进程需要将它的数据发送给另一个进程

资源共享:多个进程之间共享同样的资源。

通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进程终止时要通知父进程)。

进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另一个进程的所有陷入和异常,并能够及时知道它的状态改变

进程间通信的本质

让不同的进程先看到同一份资源(例如母亲通过孩子给父亲进行交流),由操作系统提供

匿名管道通信

我们如何让不同进程看到同一个管道文件?

通过fork创建子进程的时候实现的

pipe()

在 Linux 中,pipe() 函数是一个用于创建管道的系统调用。它允许在两个进程之间建立一个匿名的管道,实现进程间通信。

pipe() 函数的原型定义在 unistd.h 头文件中,其原型为:
int pipe(int pipefd[2]);其中,pipefd 是一个整型数组,用来存储管道的文件描述符。
pipefd[0] 用于从管道读取数据,pipefd[1] 用于向管道写入数据。


调用 pipe() 函数会创建一个管道,并将相关的文件描述符存储在 pipefd 数组中。一旦管道创建成功,就可以在父进程和子进程之间进行通信,父进程可以通过 pipefd[1] 向管道写入数据,子进程则可以通过 pipefd[0] 从管道读取数据。

vscode中保存代码:cmmand+s

管道文件大小通常是64kb

1)管道四种情况
1.正常情况,如果管道里没有数据,读端必须等待,直到有数据为止(以前我们创建父子进程,让他们各自向屏幕输出东西时,他们都会各自输出自己的,不会管对方)
2.正常情况,如果管道被写满了,写端必须等待,直到有空间为止
3.写端关闭,读端一直读取,读端会读到read返回值为0,表示读到文件结尾
4.读端关闭,写端一直写入,OS会直接杀掉写端进程,通过向目标进程发送SIGPIPE(13)信号,终止目标进程

2)管道五种特性
1.匿名管道,可以允许具有血缘关系的进程间通信,常用于父子,父孙也可以
2.匿名管道,默认给读写端提供同步机制
3.面向字节流的(可能读取出来的,不一定是完整的字符串)
4.管道的生命周期是随进程的
5.管道是单向通信的,半双工通信一种特殊情况(一方输出,一方接收)

事例

#include <iostream>
#include <unistd.h>
#include <cassert>
#include <cstring>
#include <sys/types.h>
#include <sys/wait.h>
using namespace std;#define MAX 1024int main(){// 第一步创建管道int pipefd[2] = {0};int n = pipe(pipefd);assert(n == 0);cout << "pipefd[0]: " << pipefd[0] << " " << "pipefd[0]: " << pipefd[1] << endl;// 第二步创建子进程pid_t id = fork();if (id < 0){perror("fork:");return 1;}// 子写父读// 第三步,父子关闭不需要的fd,形成单向通信的管道else if (id == 0){// child// 因为子进程使用过写管道,需要关闭读管道close(pipefd[0]);// w-只向管道写入,没有打印int cnt = 10;while (cnt--){char message[MAX];snprintf(message, sizeof(message) - 1, "hello father, I am a child,pid:%d ,cnt:%d", getpid(), cnt);write(pipefd[1], message, strlen(message));sleep(1);}}else{// father// 因为父进程使用过读管道,需要关闭写管道close(pipefd[1]);char buffer[MAX];while (true){ssize_t n = read(pipefd[0], buffer, sizeof(buffer) - 1);if (n > 0){buffer[n] = 0; // 防止末尾没有'\0'cout << getpid() << ": " << "child say: " << buffer << " " << "to me!" << endl;}}pid_t rid = waitpid(id, nullptr, 0);if (rid == id)cout << "wait success" << endl;}
}

进程池

to_string

to_string 是 C++11 中新增加的一个函数,可以将数值类型(如 int、float、double 等)转换成字符串类型。

function<void()>

function<void()>是一个函数类型,它表示一个不接受任何参数且不返回任何值的函数。在C++中,std::function是一个通用的函数封装器类模板,可以用来包装各种可调用对象,包括函数指针、函数对象、Lambda表达式等。

具体而言,std::function<void()>表示一个可以调用的函数对象,它没有参数并且没有返回值。通过将一个不接受任何参数且不返回任何值的函数或可调用对象传递给std::function<void()>,就可以创建一个可以调用的对象,该对象可以像函数一样被调用。

以下是使用std::function<void()>的示例:

#include <iostream>
#include <functional>void hello() {std::cout << "Hello, world!" << std::endl;
}int main() {std::function<void()> func = hello;func(); // 调用hello函数return 0;
}

在上述示例中,我们定义了一个名为hello的函数,它不接受任何参数并且没有返回值。然后,我们创建了一个std::function<void()>对象func,将hello函数赋值给它。最后,我们通过调用func()来调用hello函数。

需要注意的是,std::function可以用于包装各种不同类型的可调用对象,只要它们的签名(参数和返回值)与std::function的模板参数匹配即可。这使得std::function非常灵活,可以在函数指针、函数对象、Lambda表达式等之间进行切换和传递。

匿名管道的实现

processpool.cc
#include <iostream>
#include <cassert>
#include <unistd.h>
#include <string>
#include <vector>
#include <sys/types.h>
#include <sys/wait.h>
#include "task.hpp"using namespace std;
const int num = 5;
static int number = 1;class channel{
public:channel(int fd, pid_t id): ctrlfd(fd), workerid(id){name = "channel-" + to_string(number++);}int ctrlfd; // 信道pid_t workerid; // 进程idstring name; // 信道名称
};void work(){while (true){int code = 0;ssize_t n = read(0, &code, sizeof(code));if (n == sizeof(code)){if (!IN1.checksafe(code))continue;IN1.runtask(code);}else if (n == 0){break;}else{}}cout << "子进程退出" << endl;
}// 传参形式
// 1.输入参数:const &
// 2.输出参数:*
// 3.输入输出参数:&void printfd(const vector<int> &fds){cout << getpid() << "close fds:";for (auto fd : fds){cout << fd << " ";}cout << endl;
}void createchannels(vector<channel> *c){//vector<int> tmp;// 1.定义并创建管道int i = 0;for (i = 0; i < num; i++){int pipefd[2];int n = pipe(pipefd);assert(n == 0);// 2.创建进程pid_t id = fork();// 3.构建单向通信的信道if (id == 0) // child{if (!tmp.empty()){for (auto fd : tmp){close(fd);}printfd(tmp);}close(pipefd[1]);dup2(pipefd[0], 0);work();// sleep(1);exit(0);}// fatherclose(pipefd[0]);c->push_back(channel(pipefd[1], id));tmp.push_back(pipefd[1]);}
}void printdebug(vector<channel> &c){for (auto &ch : c){cout << ch.name << " " << ch.ctrlfd << " " << ch.workerid << endl;}
}void sendcommand(const vector<channel> &ch, bool flag, int num = -1){int pos = 0;while (true){// 开始完成任务// 1.选择任务int command = IN1.selecttask();// 2.选择信道const auto &c = ch[pos++];pos %= ch.size();// debugcout << "send command :" << IN1.todesc(command) << " to " << c.name << " worker is :" << c.workerid << endl;// 3.发送任务write(c.ctrlfd, &command, sizeof(command));// 4.判断是否要退出if (!flag){num--;if (num <= 0)break;}sleep(1);}cout << "发送任务完成了" << endl;
}void releasechannels(vector<channel> channels){// verson2// verson1for (const auto &ch : channels){close(ch.ctrlfd);}for (const auto &ch : channels){pid_t rid = waitpid(ch.workerid, nullptr, 0);if (rid == ch.workerid){cout << "wait child :" << ch.workerid << " success" << endl;}}
}int main(){vector<channel> channels;// 1.创建信道,创建进程createchannels(&channels);// 2.开始发送任务const bool g_always_loop = true;// sendcommand(channels,g_always_loop);sendcommand(channels, !g_always_loop, 10);// 3.回收资源,想让子进程退出,并且释放管道,只要关闭写端releasechannels(channels);return 0;
}
task.hpp
#pragma once
#include <iostream>
#include <functional>
#include <vector>
#include <ctime>
#include <unistd.h>
using namespace std;using task_t = function<void()>;// typedef function<void()> task_t;//这两种写法都一样的void download()
{cout << "我是一个下载任务" << "处理者:" << getpid() << endl;
}void printlog(){cout << "我是一个打印日志任务" << "处理者:" << getpid() << endl;
}void pushvideostream(){cout << "我是一个推送视频流任务" << "处理者:" << getpid() << endl;
}class init{// 任务码const int g_download_code = 0;const int g_printlog_code = 1;const int g_pushvideostream_code = 2;// 任务集合
public:vector<task_t> tasks;public:init(){tasks.push_back(download);tasks.push_back(printlog);tasks.push_back(pushvideostream);}bool checksafe(int code){if (code >= 0 && code < tasks.size())return true;elsereturn false;}void runtask(int code){tasks[code]();}int selecttask(){return rand() % tasks.size();}string todesc(int code){switch (code){case 0:return "download";break;case 1:return "printlog";break;case 2:return "pushvideostream";break;default:return "没有该任务";}}
};init IN1; // 定义对象
Makefile
processpool:processpool.cc
g++ -o $@ $^ -std=c++11.PHONY:clean
clean:
rm -f processpool

 🌸🌸🌸如果大家还有不懂或者建议都可以发在评论区,我们共同探讨,共同学习,共同进步。谢谢大家! 🌸🌸🌸 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/3031541.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

党务政务服务热线|基于SSM的党务政务服务热线平台(源码+数据库+文档)

目录 基于SprinBootvue的党务政务服务热线平台 一、前言 二、系统设计 三、系统功能设计 1系统功能模块 2后台功能模块 5.2.1管理员功能模块 5.2.2部门功能模块 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; …

【6大模型让你的沟通汇报更有条理】项目管理常见问题大揭秘 03

6大模型让你的沟通汇报更有条理 虽然头脑中构思众多&#xff0c;一开口却发现空白一片&#xff1f; 工作表现出色&#xff0c;汇报时却总是支支吾吾不知从何说起&#xff1f; 生性腼腆&#xff0c;却难以避免需要站在众人面前发言&#xff1f; 阿道掐指一算&#xff1a;你需…

代码无界,创新无限!华为云开发者日 · 广州站来了!

5月23日&#xff0c;2024年首场华为云开发者日HDC.Cloud Day将在广州盛大举行。这场技术派对将为开发者们带来一场无与伦比的技术盛宴。在这里&#xff0c;开发者们将有机会现场聆听行业专家的精彩分享&#xff0c;深度了解众多前沿产品的最新技术和功能&#xff0c;并与行业专…

SVN 合并到 Git 时有文件大于 100 M 被限制 Push

如果有文件大小大于 100M&#xff0c;GitHub 是会被限制推送到仓库中的&#xff0c;大概率情况会显示下面的错误&#xff1a; remote: Resolving deltas: 100% (3601/3601), done. remote: error: Trace: aea1f450da6f2ef7bfce457c715d0fbb9b0f6d428fdca80233aff34b601ff59b re…

【matlab基础知识代码】(十六)代数方程的图解法多项式型方程的准解析解方法

>> ezplot(exp(-3*t)*sin(4*t2)4*exp(-0.5*t)*cos(2*t)-0.5,[0 5]), line([0 5],[0 0]) 验证 >> t0.6738; >> exp(-3*t)*sin(4*t2)4*exp(-0.5*t)*cos(2*t)-0.5 ans -2.9852e-04 >> ezplot(x^2*exp(-x*y^2/2)exp(-x/2)*sin(x*y)) >> hold on; …

跨境电商SHEIN、Etsy、Allegro自养号测评:轻松打造热销产品

在全球化电商市场中&#xff0c;SHEIN、Etsy和Allegro等平台凭借其独特的定位和运营策略&#xff0c;吸引了大量的卖家和买家。为了在这些平台上获得更好的业务表现&#xff0c;卖家们纷纷采用自养号测评的策略来提升产品的曝光度和信誉度。本文将详细探讨在SHEIN、Etsy和Alleg…

MHD、MQA、GQA注意力机制详解

MHD、MQA、GQA注意力机制详解 注意力机制详解及代码前言&#xff1a;MHAMQAGQA 注意力机制详解及代码 前言&#xff1a; 自回归解码器推理是 Transformer 模型的 一个严重瓶颈&#xff0c;因为在每个解码步骤中加 载解码器权重以及所有注意键和值会产生 内存带宽开销 下图为三…

AGV混合型电机驱动器|伺服控制器CNS-MI50H系列对电机的要求

混合型电机驱动器 CNS-MI50H系列涵盖CNS-MI50HB-A、CNS-MI50HBN-A、CNS-MI50HDN-A、CNS-MI50HSN-A型号&#xff0c;专为 AGV 舵轮控制需求设计&#xff0c;集成舵轮转向角度控制和驱动电机闭环控制。支持增量式编码器&#xff0c;霍尔传感器&#xff0c; 角度电位计&#xff0c…

UE 解决相同按键的按键事件只会执行一次的问题

在不同蓝图有同样按键的按键事件或者是同一个蓝图但是有很多个实例&#xff0c;默认都只会执行一次事件 因为&#xff1a; 勾选Consume Input&#xff1a;当这个选项被勾选时&#xff0c;意味着你的Actor会“消耗”这个输入事件&#xff0c;阻止它继续传播到其他可能也在监听相…

GEE错误——COPERNICUS/S2_SR_HARMONIZED(Level-2A)数据中不包含QA60波段解决方案(去云解决方案)

问题 我在屏蔽哨兵-2 协调图像集中有云层覆盖的像素时遇到了一个问题。云遮蔽功能是从 GEE 文档中获取的,因此运行正常。它使用的是 "QA60 "波段。 如果不屏蔽云层像素,图像就会出现在地图画布上: 但是,如果遮挡了多云像素,则不会显示图像: 原始代码 var se…

苹果电脑怎么安装crossover 如何在Mac系统中安装CrossOver CrossOver Mac软件安装说明

很多Mac的新用户在使用电脑的过程中&#xff0c;常常会遇到很多应用软件不兼容的情况。加上自己以前一直都是用Windows系统&#xff0c;总觉得Mac系统用得很难上手。 其实&#xff0c;用户可以在Mac上安装CrossOver&#xff0c;它支持用户在Mac上运行Windows软件&#xff0c;例…

TCP协议的确认应答机制

TCP&#xff08;Transmission Control Protocol&#xff09;是一种面向连接的、可靠的、基于字节流的传输层协议&#xff0c;它在网络通信中扮演着至关重要的角色。其中&#xff0c;确认应答机制是TCP协议中的一个核心概念&#xff0c;它确保了数据的可靠传输。本文将详细介绍J…

20240511每日运维----聊聊nignx改配置所有的nginx改完unknow

1、改配置所有的nginx改完unknow src/core/nginx.h src/http/ngx_http_header_filter_module.c src/http/ngx_http_special_response.c src/http/v2/ngx_http_v2_filter_module.c 2、make 3、去objs里面把nginx文件替换过去sbin/nginx

Xbox总裁:关闭游戏工作室 确保游戏质量与长期健康发展

易采游戏网5月11日消息&#xff0c;近日微软Xbox宣布关闭旗下四家知名游戏工作室&#xff0c;这一决策在游戏界引起了广泛关注。此举并非简单的资源调整&#xff0c;而是微软为确保旗下游戏质量&#xff0c;以及Xbox平台的长期健康发展所做出的重要战略部署。 被关闭的工作室包…

锐捷EWEB网管系统RCE漏洞

文章目录 免责声明漏洞描述漏洞原理影响版本漏洞复现修复建议 免责声明 该文章只为学习和交流&#xff0c;请不要做违法乱纪的事情&#xff0c;如有与本人无关 漏洞描述 锐捷网管系统是由北京锐捷数据时代科技有限公司开发的新一代基于云的网络管理软件&#xff0c;以"…

我国吻合器市场规模不断扩大 国产化率有所增长

我国吻合器市场规模不断扩大 国产化率有所增长 吻合器是替代手工切除或缝合的一种医疗器械&#xff0c;其工作原理与订书机十分相似&#xff0c;可利用钛钉对组织进行离断或吻合。经过多年发展&#xff0c;吻合器种类逐渐增多&#xff0c;根据手术方式不同&#xff0c;吻合器大…

【每日力扣】437. 路径总和 III 与105. 从前序与中序遍历序列构造二叉树

&#x1f525; 个人主页: 黑洞晓威 &#x1f600;你不必等到非常厉害&#xff0c;才敢开始&#xff0c;你需要开始&#xff0c;才会变的非常厉害 437. 路径总和 III 给定一个二叉树的根节点 root &#xff0c;和一个整数 targetSum &#xff0c;求该二叉树里节点值之和等于 ta…

算法专题:位运算

目录 常见位运算总结 位运算相关算法题 1. 只出现一次的数字 2. 只出现一次的数字&#xff08;|||&#xff09; 3. 两整数之和 4. 只出现一次的数字&#xff08;||&#xff09; 常见位运算总结 在开始刷位运算这个类型的题目前&#xff0c;我想先带着大家学习一下一些常见…

2024年成都市企业技术中心认定申报条件要求、评价标准和时间

一、2024年成都市企业技术中心认定 &#xff08;一&#xff09;申报条件 1&#xff0e;在成都市行政区域内注册&#xff0c;具有独立法人资格。 2&#xff0e;已建立企业技术中心并正常运行1年以上。 3&#xff0e;有较强的经济、技术实力和较好的经济效益&#xff0c;在同…

Funkey游戏机新作,基于全志T113的全新版本

不同于配置高端、性能强劲的Windows、安卓掌机&#xff0c;有一部分的爱好者往往对拥有复古外形的开源掌机更加感兴趣。作为开源掌机的热门产品&#xff0c;小巧便携的FunKeys掌机是各位开源爱好者争相复刻的对象。因热爱开源掌机DIY而聚集的“双核掌机开发组”开发者团队&…