面试(十一)

news2024/11/28 14:29:38

目录

一.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].fd
         if ((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;
};
 
// API
 
int 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.coloradmin.cn/o/2249122.html

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

相关文章

Javaweb 前端 HTML css 案例 总结

顶部导航栏 弹性布局 搜索表单区域 表单标签 表单标签&#xff0c;表单项 复选&#xff0c;一次选多个 隐藏域&#xff0c;看不到&#xff0c;但会传参数 text输入框 radio单选 男女&#xff0c;是 前端页面上显示的值 搜索表单区域 button 按钮 表格数据展示区域 fo…

每日一练:【动态规划算法】斐波那契数列模型之使用最小花费爬楼梯(easy)

1. 题目链接&#xff1a;746. 使用最小花费爬楼梯 2. 题目描述 根据一般的思维&#xff0c;我们会认为本题中数组的最后一个位置是楼顶&#xff0c;但是根据第一个例子&#xff0c;如果最后一个位置是楼顶&#xff0c;花费最少应该为10&#xff0c;但是结果是15&#xff0c;因…

HCIP——堆叠技术实验配置

目录 一、堆叠的理论知识 二、堆叠技术实验配置 三、总结 一、堆叠的理论知识 1.1堆叠概述&#xff1a; 是指将两台交换机通过堆叠线缆连接在一起&#xff0c;从逻辑上变成一台交换设备&#xff0c;作为一个整体参与数据的转发。 1.2堆叠的基本概念 堆叠系统中所有的单台…

微软正在测试 Windows 11 对第三方密钥的支持

微软目前正在测试 WebAuthn API 更新&#xff0c;该更新增加了对使用第三方密钥提供商进行 Windows 11 无密码身份验证的支持。 密钥使用生物特征认证&#xff0c;例如指纹和面部识别&#xff0c;提供比传统密码更安全、更方便的替代方案&#xff0c;从而显著降低数据泄露风险…

ubuntu 安装proxychains

在Ubuntu上安装Proxychains&#xff0c;你可以按照以下步骤操作&#xff1a; 1、更新列表 sudo apt-update 2、安装Proxychains sudo apt-get install proxychains 3、安装完成后&#xff0c;你可以通过编辑/etc/proxychains.conf文件来配置代理规则 以下是一个简单的配置示例&…

数组学习后记——递归

数组这块学得有点乱,条理性欠佳。这次正好总结一下。上周的课堂内容没有更新, 因为小白自己也还没来得及吸收呢qwq。也解释一下为什么文中有这么多例题。因为我呢喜欢就着题去分析和学习,直接灌输知识不太能理解,有例子就能及时检验和应用了的。 先看看B3817 基础的双数组…

螺旋矩阵(java)

题目描述 给你一个 m 行 n 列的矩阵 matrix &#xff0c;请按照 顺时针螺旋顺序 &#xff0c;返回矩阵中的所有元素。 代码思路&#xff1a; class Solution {public List<Integer> spiralOrder(int[][] matrix) {List<Integer> list new ArrayList<>(); …

【C#设计模式(16)——解释器模式(Interpreter Pattern)】

前言 解释器模式是用来解释和执行特定的语法或表达式。它将一种表达式的规则和语义进行抽象和封装&#xff0c;然后通过解释器来解析和执行这些规则&#xff0c;将其转化为可执行的操作。 代码 //抽象表达式public interface Expression{int Interpret(Context context); //解释…

OpenHarmony属性信息怎么修改?触觉智能RK3566鸿蒙开发板来演示

本文介绍在开源鸿蒙OpenHarmony系统下&#xff0c;修改产品属性信息的方法&#xff0c;触觉智能Purple Pi OH鸿蒙开发板演示&#xff0c;搭载了瑞芯微RK3566四核处理器&#xff0c;Laval鸿蒙社区推荐开发板&#xff0c;已适配全新OpenHarmony5.0 Release系统&#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…

基础入门-Web应用架构类别源码类别镜像容器建站模版编译封装前后端分离

知识点&#xff1a; 1、基础入门-Web应用-搭建架构上的技术要点 2、基础入门-Web应用-源码类别上的技术要点 一、演示案例-架构类别-模版&分离&集成&容器&镜像 1、套用模版型 csdn / cnblog / github / 建站系统等 安全测试思路上的不同&#xff1a; 一般…

数据库操作、锁特性

1. DML、DDL和DQL是数据库操作语言的三种主要类型 1.1 DML&#xff08;Data Manipulation Language&#xff09;数据操纵语言 DML是用于检索、插入、更新和删除数据库中数据的SQL语句。 主要的DML语句包括&#xff1a; SELECT&#xff1a;用于查询数据库中的数据。 INSERT&a…

七牛智能CDN视频优化方案,展现企业长期价值

随着智能设备和视频分享平台的日益普及,视频已成为现代人记录和分享生活不可或缺的方式。这一趋势不仅使得视频制作变得简单快捷,也促使视频内容在互联网上呈现爆炸式增长。然而,这一增长同时也为企业带来了诸多挑战,包括视频文件体积增大、加载速度受限、存储和传输成本提升,以…

Qt桌面应用开发 第八天(综合项目一 飞翔的鸟)

目录 1.鸟类创建 2.鸟动画实现 3.鼠标拖拽 4.自动移动 5.右键菜单 6.窗口透明化 项目需求&#xff1a; 实现思路&#xff1a; 创建项目导入资源鸟类创建鸟动画实现鼠标拖拽实现自动移动右键菜单窗口透明化 1.鸟类创建 ①鸟类中包含鸟图片、鸟图片的最小值下标和最大值…

云技术-docker

声明&#xff01; 学习视频来自B站up主 **泷羽sec** 有兴趣的师傅可以关注一下&#xff0c;如涉及侵权马上删除文章&#xff0c;笔记只是方便各位师傅的学习和探讨&#xff0c;文章所提到的网站以及内容&#xff0c;只做学习交流&#xff0c;其他均与本人以及泷羽sec团…

《解锁计算机专业宝藏:核心编程语言与学习资料全解析》

在当今数字化浪潮汹涌澎湃、技术迭代日新月异的时代&#xff0c;计算机专业宛如一座蕴藏无尽宝藏与无限机遇的神秘殿堂&#x1f3f0;。对于莘莘学子而言&#xff0c;精准掌握核心编程语言&#xff0c;并手握优质学习资料&#xff0c;恰似寻得开启这扇殿堂大门的秘钥&#xff0c…

27加餐篇:gRPC框架的优势与不足之处

gRPC作为一个现代的、开源的远程过程调用(RPC)框架,在多个方面都展现了其优雅之处,同时也存在一些不足之处。这篇文章我们就相对全面的分析一下gRPC框架那些优雅的地方和不足的地方。 优雅的地方 gRPC作为一个RPC框架,在编码、传输协议已经支持多语言方面都比较高效,下…

Leetcode打卡:交替组II

执行结果&#xff1a;通过 题目&#xff1a;3208 交替组II 给你一个整数数组 colors 和一个整数 k &#xff0c;colors表示一个由红色和蓝色瓷砖组成的环&#xff0c;第 i 块瓷砖的颜色为 colors[i] &#xff1a; colors[i] 0 表示第 i 块瓷砖的颜色是 红色 。colors[i] 1 …

在Windows下编译支持https的wsdl2h

下载源码 在官网下载源码 安装Openssl 下载OpenSSL并安装&#xff0c;安装完成后需要将OpenSSL的路径添加到环境变量中 配置VS 1、打开工程 2、因为前面安装的OpenSLL是64位的&#xff0c;因此需要创建一个X64的配置 打开配置管理器&#xff0c;然后选择新建&#xff0…

利用Prompt工程为LLM提升推理能力

利用Prompt工程为LLM提升推理能力 基于策略的推理详解ReAct: 推理与行动思维链&#xff1a;逐步解决问题反思&#xff1a;深入分析和自我审查与代理架构的集成实际应用代码附录 众所周知&#xff0c;一个精心设计的Prompt能够显著增强大型语言模型&#xff08;LLMs&#xff09;…