面试(十一)
目录
一.IO多路复用
二.为什么有IO多路复用机制?
三.IO多路复用的三种实现方式
3.1 select
select 函数接口
select 使用示例
select 缺点
3.2 poll
poll函数接口
poll使用示例
poll缺点
3.3 epoll
epoll函数接口
epoll使用示例
epoll缺点
四. 进程和线程的区别
五. 线程和进程的通信方式都有哪些
六. 多线程并发服务器
七. 线程池
八. 深拷贝和浅拷贝
九. 内存泄漏
一.IO多路复用
IO多路复用是一种同步IO模型,实现一个线程可以监视多个文件句柄;一旦某个文件句柄就绪,就能够通知应用程序进行相应的读写操作;没有文件句柄就绪时会阻塞应用程序,交出CPU,多路是指网络连接,复用指的是同一个线程
二.为什么有IO多路复用机制?
没有IO多路复用机制时,有BIO、NIO两种实现方式,但有一些问题
同步阻塞(BIO)
· 服务端采用单线程,当accept一个请求后,在recv或send调用阻塞时,将无法accept其他请求(必须等上一个请求处recv或send完),无法处理并发
· 服务端采用多线程,当accept一个请求后,开启线程进行recv,可以完成并发处理,当随着请求数增加需要增加系统线程
同步非阻塞(NIO)
· 服务端当accept一个请求后,加入fds集合,每次轮询一遍fds集合recv(非阻塞)数据,没有数据则立即返回错误
IO多路复用
· 服务器端采用单线程通过select/epoll等系统调用获取fd列表,遍历有事件的fd列表,accept/recv/send,使其能支持更多的并发连接请求
三.IO多路复用的三种实现方式
3.1 select
select 函数接口
#include <sys/select.h>
#include <sys/time.h>#define FD_SETSIZE 1024
#define NFDBITS (8 * sizeof(unsigned long))
#define __FDSET_LONGS (FD_SETSIZE/NFDBITS)// 数据结构(bitmap)
// 用来表示一组文件描述符的状态
typedef struct
{unsigned long fds_bits[__FDSET_LONGS];
}fd_set;// API
int select{int max_fd, fd_set *readset, fd_set *writeset, fd_set *exceptset, struct timeval *timeout
}// 返回值就绪描述符的数目FD_ZERO(int fd, fd_set* fds) // 清空集合
FD_SET(int fd, fd_set* fds) // 将给定的描述符加入集合
FD_ISSET(int fd, fd_set* fds) // 判断指定描述符是否在集合中
FD_CLR(int fd, fd_set* fds) // 将给定的描述符从文件中删除
select 使用示例
int main()
{/** 这里进行一些初始化的设置,* 包括socket建立,地址的设置等,*/fd_set read_fs, write_fs;struct timeval timeout;int max = 0; // 用于记录最大的fd,在轮询中时刻更新即可// 初始化比特位FD_ZERO(&read_fs);FD_ZERO(&write_fs);int nfds = 0; // 记录就绪的事件,可以减少遍历的次数while (1) {// 阻塞获取// 每次需要把fd从用户态拷贝到内核态nfds = select(max + 1, &read_fd, &write_fd, NULL, &timeout);// 每次需要遍历所有fd,判断有无读写事件发生for (int i = 0; i <= max && nfds; ++i) {if (i == listenfd) {--nfds;// 这里处理accept事件FD_SET(i, &read_fd);//将客户端socket加入到集合中}if (FD_ISSET(i, &read_fd)) {--nfds;// 这里处理read事件}if (FD_ISSET(i, &write_fd)) {--nfds;// 这里处理write事件}}}
select 缺点
· 单个进程所打开的FD是有限制的,通过 FD_SETSIZE 设置,默认 1024
· 每次调用 select ,都需要把 fd 集合从用户态拷贝到内核态,这个开销在 fd 很多时会很大
· 对 socket 扫描时是线性扫描,采用轮询的方法,效率较低(高并发时)
3.2 poll
poll函数接口
poll与select相比,只是没有fd的限制,其它基本一样
#include <poll.h>
// 数据结构
struct pollfd {int fd; // 需要监视的文件描述符short events; // 需要内核监视的事件short revents; // 实际发生的事件
};// API
int poll(struct pollfd fds[], nfds_t nfds, int timeout);
poll使用示例
// 先宏定义长度
#define MAX_POLLFD_LEN 4096 int main() {/** 在这里进行一些初始化的操作,* 比如初始化数据和socket等。*/int nfds = 0;pollfd fds[MAX_POLLFD_LEN];memset(fds, 0, sizeof(fds));fds[0].fd = listenfd;fds[0].events = POLLRDNORM;int max = 0; // 队列的实际长度,是一个随时更新的,也可以自定义其他的int timeout = 0;int current_size = max;while (1) {// 阻塞获取// 每次需要把fd从用户态拷贝到内核态nfds = poll(fds, max+1, timeout);if (fds[0].revents & POLLRDNORM) {// 这里处理accept事件connfd = accept(listenfd);//将新的描述符添加到读描述符集合中}// 每次需要遍历所有fd,判断有无读写事件发生for (int i = 1; i < max; ++i) { if (fds[i].revents & POLLRDNORM) { sockfd = fds[i].fdif ((n = read(sockfd, buf, MAXLINE)) <= 0) {// 这里处理read事件if (n == 0) {close(sockfd);fds[i].fd = -1;}} else {// 这里处理write事件 }if (--nfds <= 0) {break; } }}}
poll缺点
· 每次调用 poll ,都需要把 fd 集合从用户态拷贝到内核态,这个开销在 fd 很多时会很大
· 对 socket 扫描时是线性扫描,采用轮询的方法,效率较低
3.3 epoll
epoll函数接口
#include <sys/epoll.h>// 数据结构
// 每一个epoll对象都有一个独立的eventpoll结构体
// 用于存放通过epoll_ctl方法向epoll对象中添加进来的事件
// epoll_wait检查是否有事件发生时,只需要检查eventpoll对象中的rdlist双链表中是否有epitem元素即可
struct eventpoll {/*红黑树的根节点,这颗树中存储着所有添加到epoll中的需要监控的事件*/struct rb_root rbr;/*双链表中则存放着将要通过epoll_wait返回给用户的满足条件的事件*/struct list_head rdlist;
};// APIint epoll_create(int size); // 内核中间加一个 ep 对象,把所有需要监听的 socket 都放到 ep 对象中
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event); // epoll_ctl 负责把 socket 增加、删除到内核红黑树
int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);// epoll_wait 负责检测可读队列,没有可读 socket 则阻塞进程
epoll使用示例
int main(int argc, char* argv[])
{/** 在这里进行一些初始化的操作,* 比如初始化数据和socket等。*/// 内核中创建ep对象epfd=epoll_create(256);// 需要监听的socket放到ep中epoll_ctl(epfd,EPOLL_CTL_ADD,listenfd,&ev);while(1) {// 阻塞获取nfds = epoll_wait(epfd,events,20,0);for(i=0;i<nfds;++i) {if(events[i].data.fd==listenfd) {// 这里处理accept事件connfd = accept(listenfd);// 接收新连接写到内核对象中epoll_ctl(epfd,EPOLL_CTL_ADD,connfd,&ev);} else if (events[i].events&EPOLLIN) {// 这里处理read事件read(sockfd, BUF, MAXLINE);//读完后准备写epoll_ctl(epfd,EPOLL_CTL_MOD,sockfd,&ev);} else if(events[i].events&EPOLLOUT) {// 这里处理write事件write(sockfd, BUF, n);//写完后准备读epoll_ctl(epfd,EPOLL_CTL_MOD,sockfd,&ev);}}}return 0;
}
epoll缺点
epoll只能工作在linux下
四. 进程和线程的区别
· 进程是资源分配的最小单位,线程是 CPU 调度的最小单位
· 一个进程可以包含多个线程,一个线程只能属于一个进程
· 进程间内存空间独立,线程间共享同一个内存地址
五. 线程和进程的通信方式都有哪些
线程间的通信
1. 共享内存:同一进程内的所有线程共享相同的地址空间,所以一个线程可以直接访问另一个线程的数据
2. 互斥锁:任何时刻只有一个线程可以访问该资源
3. 条件变量:允许线程在某个条件满足之前阻塞等待,当条件满足时被唤醒
4. 信号量:可以用来控制对共享资源的访问次数
5. 原子操作:提供了一种无需额外同步机制即可安全地更新共享数据的方法
进程间的通信
1. 管道:一种半双工的通信方式,适用于父子进程之间或者具有亲缘关系的进程之间进行通信
2. 命名管道:可以在不相关的进程之间使用,并且可以持久化到文件系统中
3. 消息队列:允许多个进程以队列的形式发送和接收信息
4. 共享内存:进程间可以通过映射同一段物理内存来进行高速数据交换
5. 信号
6. 套接字
六. 多线程并发服务器
多线程并发服务器是一种能够同时处理多个客户端请求的服务器架构
七. 线程池
线程池是一种用于管理和复用线程的技术,它预先创建了一组线程,并将这些线程保存在池中。当有任务需要执行时,从线程池中取出一个空闲的线程来处理任务,任务完成后该线程不会被销毁而是返回到线程池中等待下一次使用。这种方式可以减少频繁创建和销毁线程带来的开销。
八. 深拷贝和浅拷贝
浅拷贝:浅拷贝创建了一个新的对象,然后将原始对象中所有可变引起的对象直接复制到新对象中。
深拷贝:创建了一个新的对象,还会递归地复制原始对象中的所有子对象。新对象与原始对象完全独立,互不影响
九. 内存泄漏
程序在申请内存后,未能释放不再使用的内存。
解决措施:
1.释放资源
2.使用智能指针,自动管理生命周期
3.对象池,防止频繁创建
4.避免使用全局变量
相关文章:
面试(十一)
目录 一.IO多路复用 二.为什么有IO多路复用机制? 三.IO多路复用的三种实现方式 3.1 select select 函数接口 select 使用示例 select 缺点 3.2 poll poll函数接口 poll使用示例 poll缺点 3.3 epoll epoll函数接口 epoll使用示例 epoll缺点 四. 进程和线程的区别…...
React-useState的使用
useState 是 React 提供的一个 Hook,允许你在函数组件中添加和管理状态(state)。在类组件中,状态管理通常是通过 this.state 和 this.setState 来实现的,而在函数组件中,useState 提供了类似的功能。 基本…...
设计模式之破环单例模式和阻止破坏
目录 1. 序列化和反序列化2. 反射 这里单例模式就不多说了 23种设计模式之单例模式 1. 序列化和反序列化 这里用饿汉式来做例子 LazySingleton import java.io.Serializable;public class LazySingleton implements Serializable {private static LazySingleton lazySinglet…...
11.19c++面向对象+单例模式
编写如下类: class File{ FILE* fp }; 1:构造函数,打开一个指定的文件 2:write函数 向文件中写入数据 3:read函数,从文件中读取数据,以string类型返回 代码实现: #include <iostream>using namespace std;class…...
一文了解TensorFlow是什么
TensorFlow是一个开源的机器学习框架,由Google开发并维护。它提供了一个灵活且高效的环境,用于构建和训练各种机器学习模型。 TensorFlow的基本概念包括: 张量(Tensor):TensorFlow中的核心数据结构&#x…...

如何做好一份技术文档?
打造出色技术文档的艺术 在当今技术驱动的世界中,技术文档扮演着至关重要的角色。它不仅是工程师和开发人员之间交流的桥梁,更是产品和技术成功的隐形推手。一份优秀的技术文档宛如一张精准的航海图,能够引导读者穿越技术的迷雾,…...
Linux和Ubuntu的关系
Linux和Ubuntu的关系: 1. Linux本身是内核,Ubuntu系统是基于Linux内核的操作系统。 2. Linux内核操作系统的构成: 内核、shell、文件系统、应用程序 -应用程序:文本编辑器等 -文件系统:文件存放在存储设备上的组织方…...

软件工程之静态建模
静态模型:有助于设计包、类名、属性和方法特征标记(但不是方法体)的定义,例如UML类图。 用例的关系: 扩展关系: 扩展关系允许一个用例(可选)扩展另一个用例(基用例&…...
PICO VR串流调试Unity程序
在平时写Unity的VR程序的时候,需要调试自己写的代码,但是有的时候会发现场景过于复杂,不是HMD一体机能运行的,或者为了能够更方便的调试,不需要每次都将程序部署到眼睛里,这样非常浪费时间,对于…...

自媒体图文视频自动生成软件|03| 页面和结构介绍
代码获取方式在文本末尾🔚 *代码获取方式在文本末尾🔚 *代码获取方式在文本末尾🔚 *代码获取方式在文本末尾🔚 视频图片生成器 一个基于 Python 和 Web 的工具,用于生成带有文字和语音的视频以及图片。支持多种尺寸、…...

深入浅出摸透AIGC文生图产品SD(Stable Diffusion)
hihi,朋友们,时隔半年(24年11月),终于能腾出时间唠一唠SD了🤣,真怕再不唠一唠,就轮不到SD了,技术更新换代是在是太快! 朋友们,最近(24年2月)是真的没时间整理笔记,每天都在疯狂的学习Stable Diffusion和WebUI & ComfyUI,工作实在有点忙,实践期间在飞书上…...

解析生成对抗网络(GAN):原理与应用
目录 一、引言 二、生成对抗网络原理 (一)基本架构 (二)训练过程 三、生成对抗网络的应用 (一)图像生成 无条件图像生成: (二)数据增强 (三ÿ…...
CodeIgniter URL结构
CodeIgniter 的URL 结构设计得简洁且易于管理。通常遵循以下模式: http://<domain>/<index_page>/<controller>/<method>/<parameters> 下面是每个部分的详细说明: <domain>: 这是你的网站域名&#…...

从 App Search 到 Elasticsearch — 挖掘搜索的未来
作者:来自 Elastic Nick Chow App Search 将在 9.0 版本中停用,但 Elasticsearch 拥有你构建强大的 AI 搜索体验所需的一切。以下是你需要了解的内容。 生成式人工智能的最新进展正在改变用户行为,激励开发人员创造更具活力、更直观、更引人入…...

鸿蒙本地模拟器 模拟TCP服务端的过程
鸿蒙模拟器模拟TCP服务端的过程涉及几个关键步骤,主要包括创建TCPSocketServer实例、绑定IP地址和端口、监听连接请求、接收和发送数据以及处理连接事件。以下是详细的模拟过程: **1.创建TCPSocketServer实例:**首先,需要导入鸿蒙…...

Qt/C++基于重力模拟的像素点水平堆叠效果
本文将深入解析一个基于 Qt/C 的像素点模拟程序。程序通过 重力作用,将随机分布的像素点下落并水平堆叠,同时支持窗口动态拉伸后重新计算像素点分布。 程序功能概述 随机生成像素点:程序在初始化时随机生成一定数量的像素点,每个…...
Zookeeper学习心得
本人学zookeeper时按照此文路线学的 Zookeeper学习大纲 - 似懂非懂视为不懂 - 博客园 一、Zookeeper安装 ZooKeeper 入门教程 - Java陈序员 - 博客园 Docker安装Zookeeper教程(超详细)_docker 安装zk-CSDN博客 二、 zookeeper的数据模型 ZooKeepe…...
嵌入式开发工程师面试题 - 2024/11/24
原文嵌入式开发工程师面试题 - 2024/11/24 转载请注明来源 1.若有以下定义语句double a[8],*pa;int i5;对数组元素错误的引用是? A *a B a[5] C *(p1) D p[8] 解析: 在 C 或 C 语言中&am…...

Python中打印当前目录文件树的脚本
效果图: 实现脚本: 1、显示所有文件和文件夹: import osdef list_files(startpath, prefix):items os.listdir(startpath)items.sort()for index, item in enumerate(items):item_path os.path.join(startpath, item)is_last index le…...

全景图像(Panorama Image)向透视图像(Perspective Image)的跨视图转化(Cross-view)
一、概念讲解 全景图像到透视图像的转化是一个复杂的图像处理过程,它涉及到将一个360度的全景图像转换为一个具有透视效果的图像,这种图像更接近于人眼观察世界的方式。全景图像通常是一个矩形图像,它通过将球面图像映射到平面上得到…...
Cursor实现用excel数据填充word模版的方法
cursor主页:https://www.cursor.com/ 任务目标:把excel格式的数据里的单元格,按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例,…...
rknn优化教程(二)
文章目录 1. 前述2. 三方库的封装2.1 xrepo中的库2.2 xrepo之外的库2.2.1 opencv2.2.2 rknnrt2.2.3 spdlog 3. rknn_engine库 1. 前述 OK,开始写第二篇的内容了。这篇博客主要能写一下: 如何给一些三方库按照xmake方式进行封装,供调用如何按…...

.Net框架,除了EF还有很多很多......
文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...
深入浅出:JavaScript 中的 `window.crypto.getRandomValues()` 方法
深入浅出:JavaScript 中的 window.crypto.getRandomValues() 方法 在现代 Web 开发中,随机数的生成看似简单,却隐藏着许多玄机。无论是生成密码、加密密钥,还是创建安全令牌,随机数的质量直接关系到系统的安全性。Jav…...

(二)原型模式
原型的功能是将一个已经存在的对象作为源目标,其余对象都是通过这个源目标创建。发挥复制的作用就是原型模式的核心思想。 一、源型模式的定义 原型模式是指第二次创建对象可以通过复制已经存在的原型对象来实现,忽略对象创建过程中的其它细节。 📌 核心特点: 避免重复初…...

从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)
设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile,新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...
大模型多显卡多服务器并行计算方法与实践指南
一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...

听写流程自动化实践,轻量级教育辅助
随着智能教育工具的发展,越来越多的传统学习方式正在被数字化、自动化所优化。听写作为语文、英语等学科中重要的基础训练形式,也迎来了更高效的解决方案。 这是一款轻量但功能强大的听写辅助工具。它是基于本地词库与可选在线语音引擎构建,…...

html css js网页制作成品——HTML+CSS榴莲商城网页设计(4页)附源码
目录 一、👨🎓网站题目 二、✍️网站描述 三、📚网站介绍 四、🌐网站效果 五、🪓 代码实现 🧱HTML 六、🥇 如何让学习不再盲目 七、🎁更多干货 一、👨…...

【Redis】笔记|第8节|大厂高并发缓存架构实战与优化
缓存架构 代码结构 代码详情 功能点: 多级缓存,先查本地缓存,再查Redis,最后才查数据库热点数据重建逻辑使用分布式锁,二次查询更新缓存采用读写锁提升性能采用Redis的发布订阅机制通知所有实例更新本地缓存适用读多…...