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://www.mzph.cn/pingmian/12015.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

下单制造fpc的工艺参数

FPC工艺简介 - 百度文库 (baidu.com) FPC工艺参数 - 豆丁网 (docin.com) FPC柔性线路板的主要参数.ppt (book118.com) 捷多邦&#xff1a; 华秋&#xff1a; 背胶&#xff1a; FPC板背胶是可以粘接在光滑表面的一种薄型胶带&#xff0c;可以在狭小以及光滑的表面上用来提供高…

互联网医院源码|禾高互联网医院系统功能和优势

互联网医院系统是一种建立在互联网基础上的医疗服务平台&#xff0c;其目标是通过数字化手段改善患者和医生之间的医疗互动。这一系统不仅使患者能够更轻松地获取医疗服务&#xff0c;而且也为医生提供了更灵活的工作方式。 1、智能导诊:提供人体模拟图&#xff0c;模拟门诊医生…

【学习笔记】C++每日一记[20240513]

简述静态全局变量的概念 在全局变量前加上static关键字&#xff0c;就定义了一个静态全局变量。通常情况下&#xff0c;静态全局变量的声明和定义放在源文件中&#xff0c;并且不能使用extern关键字将静态全局变量导出&#xff0c;因此静态全局变量的**作用于仅限于定义静态全…

振弦式应变计的与实际测量值不一致怎么办

在进行结构健康监测或其他工程测量时&#xff0c;精确性和可靠性至关重要。振弦式表面应变计是一种广泛使用的测量工具&#xff0c;它通过测量材料表面的应变来评估结构的应力状态。然而&#xff0c;在实际应用中&#xff0c;振弦式应变计的测量值与实际应变值之间的不一致问题…

【JavaScript】---- 使用 Tween 实现转盘抽奖

1. 实现效果 2. 需求分析 它和正常的转盘抽奖不一样&#xff0c;一般实现都是指针形式的&#xff0c;转盘转动&#xff0c;最后指针停留在奖品的随机位置&#xff1b;通过上边图发现奖品必须刚好停留在奖品的位置&#xff0c;因为不是指针&#xff0c;所以不能最后落到随机位置…

福建聚鼎:做装饰画到底能不能赚钱

在探讨做装饰画能否成为盈利的行当之前&#xff0c;我们必须认识到任何一门艺术或手工的价值并非仅仅取决于其直接的经济收益。艺术创作本身就是一种文化传承和个人情感表达的方式&#xff0c;它对创作者和社会都有着不可估量的精神价值。然而&#xff0c;将话题限定在经济回报…

武汉星起航跨境电商:亚马逊自发货订单处理全流程解析

在亚马逊电商平台上&#xff0c;自发货订单的处理是卖家日常运营中的重要环节。正确的处理流程不仅能确保交易的顺畅进行&#xff0c;还能提升买家满意度&#xff0c;进而促进销售业绩的提升。武汉星起航在这里整理了亚马逊自发货订单的处理流程&#xff0c;帮助卖家更好地管理…

基于ChatGPT 和 OpenAI 模型的现代生成式 AI

书籍&#xff1a;Modern Generative AI with ChatGPT and OpenAI Models: Leverage the capabilities of OpenAIs LLM for productivity and innovation with GPT3 and GPT4 作者&#xff1a;Valentina Alto 出版&#xff1a;Packt Publishing 书籍下载-《基于ChatGPT 和 Op…

4 局域网技术(一):局域网概述

目录 1 局域网概述1.1 局域网的特点1.2 局域网的介质访问控制方法1、具有冲突检测的载波侦听多路访问&#xff08;CSMA/CD&#xff09;对几个概念进行解释CSMA/CD的说明 2、令牌&#xff08;Token&#xff09;技术 1.3 网络适配器1、网络适配器的功能2、网卡的总类3、Ethernet网…

视频太大了?这2招轻松完成在线视频压缩

在当今数字媒体时代&#xff0c;视频文件的大小往往是一个让人头疼的问题。无论是拍摄的素材、编辑的成品还是下载的内容&#xff0c;过大的视频文件不仅占用大量存储空间&#xff0c;还可能影响传输速度和播放流畅度。那么&#xff0c;如何轻松完成在线视频压缩&#xff0c;减…

【网络安全产品互联互通 告警信息资产信息】相关思维导图

近日&#xff0c;在某客户安全建设项目中&#xff0c;涉及安全告警事件的梳理上报。在整理及学习中发现最近&#xff08;以19年等保2.0为参考分隔“最近”&#xff09;发布的可参考标准&#xff0c;因此做了思维导图的整理。 PS&#xff1a;标准中存在引用的情况&#xff0c;过…

数字序列比大小 - 贪心思维

系列文章目录 文章目录 系列文章目录前言一、题目描述二、输入描述三、输出描述四、java代码五、测试用例 前言 本人最近再练习算法&#xff0c;所以会发布自己的解题思路&#xff0c;希望大家多指教 一、题目描述 A&#xff0c;B两个人万一个数字的游戏&#xff0c;在游戏前…

ansible利用playbook 部署lamp架构

搭建参考&#xff1a;ansible批量运维管理-CSDN博客 定义ansible主机清单 [rootansible-server ~]# vim /etc/hosts 192.168.200.129 host01 192.168.200.130 host02 [rootansible-server ~]# vim /etc/ansible/hosts [webserver] host01 host02 在ansible端编写index.html…

OpenAI 把超强AI带进日常,GPT-4o 让机器也懂情感!

一、前言 ⭐⭐ 立即体验&#xff1a;GPT-4o OpenAI 在春季发布会上推出了名为 GPT-4o 的旗舰级生成式人工智能模型&#xff0c;这一模型的发布不仅标志着技术的巨大飞跃&#xff0c;更预示着人机交互方式的全面革新。"o" 在 GPT-4o 中代表 "omni"&#xf…

使用 Express 框架构建的 Node.js web 应用程序

使用 Express 框架构建的 Node.js web 应用程序 ├── config │ └── config.js ├── middlewares │ └── errorHandler.js ├── routes │ ├── index.js │ ├── postRoutes.js │ └── userRoutes.js ├── .env ├── .gitignore ├── app.js ├…

新手必看:页面设计与网页设计的区别及应用指南

页面设计和网页设计都是创建网页的过程&#xff0c;但页面设计的焦点和目的与网页设计不同。页面设计往往更注重网站的视觉和交互设计&#xff0c;而网页设计则侧重于整个网站的架构和功能设计。本文将具体介绍页面设计与网页设计的区别&#xff0c;新手小看必看&#xff01; …

腾讯宣布混元文生图大模型开源: Sora 同架构,可免费商用

5月14日&#xff0c;腾讯宣布旗下的混元文生图大模型全面升级并对外开源&#xff0c;目前已在 Hugging Face 平台及 Github 上发布&#xff0c;包含模型权重、推理代码、模型算法等完整模型&#xff0c;可供企业与个人开发者免费商用。 这是业内首个中文原生的DiT架构文生图开…

YOLOv8_seg训练流程-原理解析[实例分割理论篇]

本篇将介绍一下YOLOv8实例分割网络的训练流程,同样在看此篇文章之前先去看一下预测流程YOLOv8_seg预测流程-原理解析[实例分割理论篇]-CSDN博客 ,还有目标检测任务的训练流程YOLOv8训练流程-原理解析[目标检测理论篇]-CSDN博客 ,这两篇都是前置课程,下图是YOLOv8实例分割的…

八字排盘软件-​无敌八字排盘软件

功能介绍 1.完全免费使用&#xff0c;即使用不需要付费且无任何限制。 2.同时推出手机版电脑版&#xff0c;两版本数据互通互用&#xff0c;即电脑版的数据可以备份到手机版上导入&#xff0c;手机版的数据也可以备份到电脑版上恢复导入&#xff0c;方便手机和电脑共用的朋友。…

基于Springboot汽车租赁预约管理系统

一&#xff1a;功能介绍 本系统是Springboot项目采用的技术栈主要有Spring、mybaits、springboot、mysql数据库 功能角色主要分为管理员、超级管理员、用户等几个角色 二&#xff1a;功能截图 三&#xff1a;源码获取