面试(十一)

目录

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Spring Boot框架:英语知识网站构建指南

3系统分析 3.1可行性分析 通过对本英语知识应用网站实行的目的初步调查和分析&#xff0c;提出可行性方案并对其一一进行论证。我们在这里主要从技术可行性、经济可行性、操作可行性等方面进行分析。 3.1.1技术可行性 本英语知识应用网站采用SSM框架&#xff0c;JAVA作为开发语…

路由器中继与桥接

一 . 背景 现在的路由器大多数已经开始支持多种网络连接模式&#xff0c;以下将以TP-Link迷你无线路由器为例进行展开介绍。在TP-Link迷你无线路由器上一般有AP&#xff08;接入点&#xff09;模式&#xff0c;Router&#xff08;无线路由&#xff09;模式&#xff0c;Repeate…

Paddle Inference部署推理(一)

一&#xff1a;Paddle Inference推理 简介 Paddle Inference 是飞桨的原生推理库&#xff0c;提供服务器端的高性能推理能力。由于 Paddle Inference 能力直接基于飞桨的训练算子&#xff0c;因此它支持飞桨训练出的所有模型的推理。 Paddle Inference 功能特性丰富&#xff…

前端 vue3 + element-plus + ts 对话框示例

【父组件】&#xff1a;SampleInput.vue&#xff0c;局部代码片段 引入子组件 ApplyItemChooseDialog.vue&#xff0c;定义变量&#xff0c;用于渲染和显示标识 <script>片段代码 import ApplyItemChooseDialog from "/views/accept/ApplyItemChooseDialog.vue&q…

【最优清零方案——贪心+滑动窗口:暴力/线段树/单调队列】

题目 暴力 #include <bits/stdc.h> using namespace std; using ll long long; const int N 1e6 10; int a[N]; int main() {int n, k;cin >> n >> k;ll sum 0;for (int i 1; i < n; i)cin >> a[i], sum a[i];int minn 1e9, pos;ll cnt 0…

Python爬取豆瓣电影全部分类数据并存入数据库

在当今数字化的时代&#xff0c;网络上丰富的影视资源信息吸引着众多开发者去挖掘和利用。今天&#xff0c;我就来和大家分享一段有趣的代码&#xff0c;它能够从豆瓣电影平台获取相关数据并存储到数据库中哦。 结果展示&#xff08;文末附完整代码&#xff09;&#xff1a; 目…

数据结构 ——— 归并排序算法的实现

目录 归并排序的思想 归并排序算法的实现 归并排序的思想 将已经有序的子序列合并&#xff0c;得到完全有序的序列&#xff0c;即先使每个子序列有序后&#xff0c;再使子序列段间有序 若将两个有序表合并成一个有序表&#xff0c;称为二路归并 归并排序步骤示意图&#x…

vue2面试题11|[2024-11-25]

1.vue源码-模版解析 <!DOCTYPE html> <html> <head><title></title> </head> <body><div idapp><h1> {{ str }} </h1>{{ str }} </div></body><script type"text/javascript" srcvue.js…

web博客系统的自动化测试

目录 前言测试用例编写自动化脚本测试准备博客登录页相关测试用例登陆成功登录失败 博客首页相关测试用例登陆成功登录失败 博客详情页相关测试用例登录成功登录失败 博客编辑页相关测试用例登陆成功登录失败 编写测试文档测试类型内容 前言 本次测试是运用个人写的一个博客系…

MATLAB矩阵元素的修改及删除

利用等号赋值来进行修改 A ( m , n ) c A(m,n)c A(m,n)c将将矩阵第 m m m行第 n n n列的元素改为 c c c&#xff0c;如果 m m m或 n n n超出原来的行或列&#xff0c;则会自动补充行或列&#xff0c;目标元素改为要求的&#xff0c;其余为 0 0 0 A ( m ) c A(m)c A(m)c将索引…

告别 Kafka,拥抱 Databend:构建高效低成本的用户行为分析体系

用户行为数据埋点指标是数据仓库中不可或缺的重要数据源之一&#xff0c;同时也是企业最宝贵的资产之一。通常情况下&#xff0c;用户行为数据分析包含两大数据源&#xff1a;用户行为分析日志和上游关系型数据库&#xff08;如 MySQL&#xff09;。基于这些数据&#xff0c;企…

WEB攻防-通用漏洞文件上传中间件解析漏洞编辑器安全

中间件文件解析-IIS&Apache&Nginx Web应用编辑器-Ueditor文件上传安全 实例CMS&平台-中间件解析&编辑器引用 Vulhub是一个基于docker和docker-compose的漏洞环境集合&#xff0c;进入对应目录并执行一条语句即可启动一个全新的漏洞环境&#xff0c;让漏洞复现…

【算法day1】数组:双指针算法

题目引用 这里以 1、LeetCode704.二分查找 2、LeetCode27.移除元素 3、LeetCode977.有序数组的平方 这三道题举例来说明数组中双指针的妙用。 1、二分查找 给定一个 n 个元素有序的&#xff08;升序&#xff09;整型数组 nums 和一个目标值 target &#xff0c;写一个函数搜…

快速理解微服务中Sentinel怎么实现限流

Sentinel是通过动态管理限流规则&#xff0c;根据定义的规则对请求进行限流控制。 一.实现步骤 1.定义资源&#xff1a;在Sentinel中&#xff0c;资源可以是URL、方法等&#xff0c;用于标识需要进行限流的请求&#xff1b;(在Sentinel中&#xff0c;需要我们去告诉Sentinel哪些…

controller中的参数注解@Param @RequestParam和@RequestBody的不同

现在controller中有个方法&#xff1a;&#xff08;LoginUserRequest是一个用户类对象&#xff09; PostMapping("/test/phone")public Result validPhone(LoginUserRequest loginUserRequest) {return Result.success(loginUserRequest);}现在讨论Param("login…

OpenCV截取指定图片区域

import cv2 img cv2.imread(F:/2024/Python/demo1/test1/man.jpg) cv2.imshow(Image, img) # 显示图片 #cv2.waitKey(0) # 等待按键x, y, w, h 500, 100, 200, 200 # 示例坐标 roi img[y:yh, x:xw] # 截取指定区域 cv2.imshow(ROI, roi) cv2.waitKey(0) cv…

【经典】星空主题的注册界面HTML,CSS,JS

目录 界面展示 完整代码 说明&#xff1a; 这是一个简单的星空主题的注册界面&#xff0c;使用了 HTML 和 CSS 来实现一个背景为星空效果的注册页面。 界面展示 完整代码 <!DOCTYPE html> <html lang"zh"> <head><meta charset"UTF-8&…

后端:事务

文章目录 1. 事务2. Spring 单独配置DataSource3. 利用JdbcTemplate操作数据库4. 利用JdbcTemplate查询数据5. Spring 声明式事务6. 事务的隔离级别6.1 脏读6.2 不可重复读6.3 幻读6.4 不可重复读和幻读的区别6.5 三种方案的比较 7. 事务的传播特性8. 设置事务 只读(readOnly)9…

vue element-ui的el-image 和 el-table冲突层级冲突问题问题preview-teleported

问题: 解决代码:preview-teleported <el-image style"width: 50px; height: 50px" :src"props.row.url" :zoom-rate"1.2" :max-scale"7":min-scale"0.2" :preview-src-list"[props.row.url]" :initial-index&…

vue3 开发利器——unplugin-auto-import

这玩意儿是干啥的&#xff1f; 还记得 Vue 3 的组合式 API 语法吗&#xff1f;如果有印象&#xff0c;那你肯定对以下代码有着刻入 DNA 般的熟悉&#xff1a; 刚开始写觉得没什么&#xff0c;但是后来渐渐发现&#xff0c;这玩意儿几乎每个页面都有啊&#xff01; 每次都要写…