面试(十一)

目录

一.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.避免使用全局变量

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

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

相关文章

Java中的线程池使用详解

文章目录 Java中的线程池使用详解一、引言二、线程池的创建与使用1、线程池的创建1.1、FixedThreadPool&#xff08;固定大小线程池&#xff09;1.2、CachedThreadPool&#xff08;可缓存线程池&#xff09;1.3、SingleThreadExecutor&#xff08;单线程化线程池&#xff09;1.…

3D扫描对文博行业有哪些影响?

三维扫描技术对文博行业产生了深远的影响&#xff0c;主要体现在以下几个方面&#xff1a; 一、高精度建模与数字化保护 三维扫描技术通过高精度扫描设备&#xff0c;能够捕捉到文物的每一个细节&#xff0c;包括形状、纹理、颜色等&#xff0c;从而生成逼真的3D模型。这些模…

C# 泛型(Generic)

文章目录 前言一、泛型的基本概念与实例展示二、泛型的特性与优势三、泛型方法四、泛型委托 前言 泛型&#xff08;Generic&#xff09;允许将类或方法中编程元素的数据类型规范进行延迟编写&#xff0c;直到在程序实际使用这些类或方法的时候再去确定具体的数据类型。 一、泛…

前端小练习——星辰宇宙(JS没有上限!!!)

前言&#xff1a;在刚开始学习前端的时候&#xff0c;我们会学习到前端三件套中的JavaScript&#xff0c;可能那时候读者没有觉得JavaScript这个语言有多么的牛逼&#xff0c;本篇文章将会使用一个炫酷的案例来刷新你对JavaScript这个语言的认知与理解。 ✨✨✨这里是秋刀鱼不做…

【Python爬虫五十个小案例】爬取豆瓣电影Top250

博客主页&#xff1a;小馒头学python 本文专栏: Python爬虫五十个小案例 专栏简介&#xff1a;分享五十个Python爬虫小案例 &#x1fab2;前言 在这篇博客中&#xff0c;我们将学习如何使用Python爬取豆瓣电影Top250的数据。我们将使用requests库来发送HTTP请求&#xff0c;…

多目标优化算法——多目标粒子群优化算法(MOPSO)

Handling Multiple Objectives With Particle Swarm Optimization&#xff08;多目标粒子群优化算法&#xff09; 一、摘要&#xff1a; 本文提出了一种将帕累托优势引入粒子群优化算法的方法&#xff0c;使该算法能够处理具有多个目标函数的问题。与目前其他将粒子群算法扩展…

C++设计模式——Singleton单例模式

一、单例模式的定义 单例模式&#xff0c;英文全称Singleton Pattern&#xff0c;是一种创建型设计模式&#xff0c;它保证一个类在程序中仅有一个实例&#xff0c;并对外提供一个访问的该类实例的全局接口。 单例模式通常用于需要控制对象资源的开发场景&#xff0c;一个类…

Python学习35天

# 定义父类 class Computer: CPUNone MemoryNone diskNone def __init__(self,CPU,Memory,disk): self.disk disk self.Memory Memory self.CPU CPU def get_details(self): return f"CPU:{self.CPU}\tdisk:{self.disk}\t…

<项目代码>YOLOv8 停车场空位识别<目标检测>

YOLOv8是一种单阶段&#xff08;one-stage&#xff09;检测算法&#xff0c;它将目标检测问题转化为一个回归问题&#xff0c;能够在一次前向传播过程中同时完成目标的分类和定位任务。相较于两阶段检测算法&#xff08;如Faster R-CNN&#xff09;&#xff0c;YOLOv8具有更高的…

mac下Gpt Chrome升级成GptBrowser书签和保存的密码恢复

cd /Users/自己的用户名/Library/Application\ Support/ 目录下有 GPT\ Chrome/ Google/ GptBrowser/ GPT\ Chrome 为原来的chrome浏览器的文件存储目录. GptBrowser 为升级后chrome浏览器存储目录 书签所在的文件 Bookmarks 登录账号Login 相关的文件 拷贝到GptBrow…

GB28181系列二:SIP信令

我的音视频/流媒体开源项目(github) GB28181系列目录 目录 一、SIP报文介绍 二、SIP交互流程&#xff1a; 1、Session Model 2、Pager Model 3、SIP信令交互过程中的3个定义 三、媒体传输&#xff08;SDP和RTP&#xff09; 一、SIP报文介绍 这里将会介绍SIP…

ViSTa:一个包含4000多个视频和逐步描述的层次化数据集,用于评估VLMs在不同复杂性任务中的表现。

2024-11-22&#xff0c;由Google DeepMind和MATS机构创建的ViSTa数据集&#xff0c;为评估视觉语言模型&#xff08;VLMs&#xff09;在理解基于顺序的任务方面的能力提供了新的视角&#xff0c;这对于强化学习中的成本降低和安全性提升具有重要意义。 数据集地址&#xff1a;…

区块链:波场-TRON链

注意: 1、调试时请将所有的API地址都换成 https://api.trongrid.io 以免报错等问题 https://api.trongrid.io 主网 (Mainnet) 适用于生产环境 https://api.shasta.trongrid.io 测试网 (Shasta) 适用于开发者测试 https://nile.trongrid.io 测试网 (Nile) …

【适配】屏幕拖拽-滑动手感在不同分辨率下的机型适配

接到一个需求是类似下图的3D多房间视角&#xff0c;需要拖拽屏幕 问题 在做这种屏幕拖拽的时候发现&#xff0c;需要拖拽起来有跟手的感觉&#xff0c;会存在不同分辨率机型的适配问题。 即&#xff1a;美术调整好了机型1的手感&#xff0c;能做到手指按下顶层地板上下挪动&…

比特币libsecp256k1中safegcd算法形式化验证完成

1. 引言 比特币和其他链&#xff08;如 Liquid&#xff09;的安全性取决于 ECDSA 和 Schnorr 签名等数字签名算法的使用。Bitcoin Core 和 Liquid 都使用名为 libsecp256k1 的 C 库来提供这些数字签名算法&#xff0c;该库以其所运行的椭圆曲线命名。这些算法利用一种称为modu…

『VUE』elementUI dialog的子组件created生命周期不刷新(详细图文注释)

目录 1. 测试代码分析令人迷惑的效果 分析原因解决方法 如何在dialog中反复触发created呢?总结 欢迎关注 『VUE』 专栏&#xff0c;持续更新中 欢迎关注 『VUE』 专栏&#xff0c;持续更新中 主要是在做表单的时候想要有一个编辑表单在dialog弹窗中出现,同时dialog调用的封装的…

深入探讨 Redis 持久化机制:原理、配置与优化策略

文章目录 一、引言二、Redis持久化概述三、RDB&#xff08;Redis DataBase&#xff09;持久化1、RDB概念与工作原理2、RDB的配置选项3、RDB优化配置项4、RDB的优势与劣势 三、AOF&#xff08;Append-Only File&#xff09;持久化1、AOF概念与工作原理2、AOF的三种写回策略3、Re…

使用爬虫时,如何确保数据的准确性?

在数字化时代&#xff0c;数据的准确性对于决策和分析至关重要。本文将探讨如何在使用Python爬虫时确保数据的准确性&#xff0c;并提供代码示例。 1. 数据清洗 数据清洗是确保数据准确性的首要步骤。在爬取数据后&#xff0c;需要对数据进行清洗&#xff0c;去除重复、无效和…

(计算机网络)期末

计算机网络概述 物理层 信源就是发送方 信宿就是接收方 串行通信--一次只发一个单位的数据&#xff08;串行输入&#xff09; 并行通信--一次可以传输多个单位的数据 光纤--利用光的反射进行传输 传输之前&#xff0c;要对信源进行一个编码&#xff0c;收到信息之后要进行一个…

111. UE5 GAS RPG 实现角色技能和场景状态保存到存档

实现角色的技能存档保存和加载 首先&#xff0c;我们在LoadScreenSaveGame.h文件里&#xff0c;增加一个结构体&#xff0c;用于存储技能相关的所有信息 //存储技能的相关信息结构体 USTRUCT(BlueprintType) struct FSavedAbility {GENERATED_BODY()//需要存储的技能UPROPERT…