当前位置: 首页 > news >正文

termios 线程 poll epoll进化 二叉AVL红黑树

struct termios tio 是什么

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>#define SERIAL_PORT "/dev/ttyS0"
#define BUF_SIZE    256int main(void)
{int fd;struct termios tio;/* 1. 打开串口 */fd = open(SERIAL_PORT, O_RDWR | O_NOCTTY | O_SYNC);if (fd < 0) {perror("open");return 1;}/* 2. 配置串口:115200 8N1,无流控 */memset(&tio, 0, sizeof(tio));cfsetospeed(&tio, B115200);cfsetispeed(&tio, B115200);tio.c_cflag &= ~PARENB;        /* 无校验 */tio.c_cflag &= ~CSTOPB;        /* 1 停止位 */tio.c_cflag &= ~CSIZE;tio.c_cflag |= CS8;            /* 8 数据位 */tio.c_cflag |= (CLOCAL | CREAD);tio.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); /* 原始模式 */tio.c_iflag &= ~(IXON | IXOFF | IXANY);         /* 无软件流控 */tio.c_oflag &= ~OPOST;                          /* 原始输出 */tcflush(fd, TCIOFLUSH);tcsetattr(fd, TCSANOW, &tio);/* 3. 写入数据 */char *tx = "hello world\n";if (write(fd, tx, strlen(tx)) < 0) {perror("write");close(fd);return 1;}/* 4. 循环读取并查找 "flush" */char buf[BUF_SIZE];int len, total = 0;char line[BUF_SIZE * 2] = {0};while (1) {len = read(fd, buf, sizeof(buf));if (len < 0) {perror("read");break;}if (len == 0)continue;/* 把新数据追加到 line 缓冲区 */if (total + len < sizeof(line) - 1) {memcpy(line + total, buf, len);total += len;line[total] = '\0';}/* 判断是否出现 "flush" */if (strstr(line, "flush")) {printf("Received \"flush\", exit.\n");break;}/* 打印刚收到的数据(可选) */printf("Rx[%d]: %.*s", len, len, buf);fflush(stdout); //立即刷新缓冲区//把 C 标准库 为 `stdout`(通常是终端)维护的用户态缓冲区立即刷到内核,确保之前 `printf/puts` 的内容立刻出现在屏幕上}close(fd);return 0;
}
  • pthread_create
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <pthread.h>#define SERIAL_PORT "/dev/ttyS0"
#define BUF_SIZE    256static int stop = 0;            /* 线程退出标志 */
static pthread_t tid;/* 串口初始化:115200 8N1,阻塞读 */
static int open_serial(void)
{int fd = open(SERIAL_PORT, O_RDWR | O_NOCTTY);if (fd < 0) {perror("open " SERIAL_PORT);return -1;}struct termios tio;tcgetattr(fd, &tio);cfmakeraw(&tio);cfsetispeed(&tio, B115200);cfsetospeed(&tio, B115200);tcflush(fd, TCIOFLUSH);tcsetattr(fd, TCSANOW, &tio);return fd;
}/* 线程函数:一直读串口直到看到 "flush" */
static void *rx_thread(void *arg)
{int fd = (long)arg;char buf[BUF_SIZE];char line[BUF_SIZE * 2] = {0};int total = 0;while (!stop) {int n = read(fd, buf, sizeof(buf));if (n <= 0) continue;/* 追加到行缓冲区并检查子串 */if (total + n < sizeof(line) - 1) {memcpy(line + total, buf, n);total += n;line[total] = '\0';}if (strstr(line, "flush")) {printf("[RX-THREAD] Found \"flush\", exiting.\n");break;}}close(fd);return NULL;
}int main(void)
{int fd = open_serial();if (fd < 0) return 1;/* 创建接收线程 */if (pthread_create(&tid, NULL, rx_thread, (void *)(long)fd) != 0) {perror("pthread_create");close(fd);return 1;}/* 主线程可以干别的事,这里简单等待用户输入 */printf("Press Enter to quit...\n");getchar();/* 通知线程退出并等待结束 */stop = 1;pthread_cancel(tid);    /* 若线程阻塞在 read(),可强制唤醒 */pthread_join(tid, NULL);printf("Main thread exit.\n");return 0;
}
  • poll
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <poll.h>#define SERIAL_PORT "/dev/ttyS0"
#define BUF_SIZE    256static int open_serial(void)
{int fd = open(SERIAL_PORT, O_RDWR | O_NOCTTY | O_NONBLOCK);if (fd < 0) { perror("open"); return -1; }struct termios tio;tcgetattr(fd, &tio);cfmakeraw(&tio);cfsetispeed(&tio, B115200);cfsetospeed(&tio, B115200);tcflush(fd, TCIOFLUSH);tcsetattr(fd, TCSANOW, &tio);return fd;
}int main(void)
{int fd = open_serial();if (fd < 0) return 1;char line[BUF_SIZE * 2] = {0};int total = 0;struct pollfd pfd = { .fd = fd, .events = POLLIN };while (1) {int ret = poll(&pfd, 1, -1);        /* 无限等待可读 */if (ret < 0) { perror("poll"); break; }if (pfd.revents & POLLIN) {char buf[BUF_SIZE];int n = read(fd, buf, sizeof(buf));if (n <= 0) continue;/* 追加到行缓冲并检查 */if (total + n < sizeof(line) - 1) {memcpy(line + total, buf, n);total += n;line[total] = '\0';}if (strstr(line, "flush")) {printf("Got flush, exit.\n");break;}}}close(fd);return 0;
}
  • epoll
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <sys/epoll.h>#define SERIAL_PORT "/dev/ttyS0"
#define BUF_SIZE    256
#define MAX_EVENTS  1static int open_serial(void)
{int fd = open(SERIAL_PORT, O_RDWR | O_NOCTTY | O_NONBLOCK);if (fd < 0) { perror("open"); return -1; }struct termios tio;tcgetattr(fd, &tio);cfmakeraw(&tio);cfsetispeed(&tio, B115200);cfsetospeed(&tio, B115200);tcflush(fd, TCIOFLUSH);tcsetattr(fd, TCSANOW, &tio);return fd;
}int main(void)
{int fd = open_serial();if (fd < 0) return 1;int epfd = epoll_create1(0);if (epfd < 0) { perror("epoll_create1"); return 1; }struct epoll_event ev = { .events = EPOLLIN, .data.fd = fd };if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev) < 0) {perror("epoll_ctl"); return 1;}char line[BUF_SIZE * 2] = {0};int total = 0;struct epoll_event events[MAX_EVENTS];while (1) {int nfds = epoll_wait(epfd, events, MAX_EVENTS, -1);if (nfds < 0) { perror("epoll_wait"); break; }for (int i = 0; i < nfds; ++i) {if (events[i].events & EPOLLIN) {char buf[BUF_SIZE];int n = read(fd, buf, sizeof(buf));if (n <= 0) continue;if (total + n < sizeof(line) - 1) {memcpy(line + total, buf, n);total += n;line[total] = '\0';}if (strstr(line, "flush")) {printf("Got flush, exit.\n");goto out;}}}}
out:close(fd);close(epfd);return 0;
}

深入浅出理解select、poll、epoll的实现

selectpollepoll
性能随着连接数的增加,性能急剧下降,处理成千上万的并发连接数时,性能很差随着连接数的增加,性能急剧下降,处理成千上万的并发连接数时,性能很差随着连接数的增加,性能基本没有变化
连接数一般1024无限制无限制
内存拷贝每次调用select拷贝每次调用poll拷贝fd首次调用epoll_ctl拷贝,每次调用epoll_wait不拷贝
数据结构bitmap数组红黑树
内在处理机制线性轮询线性轮询FD挂在红黑树,通过事件回调callback
时间复杂度O(n)O(n)O(1)

目前支持I/O多路复用的系统调用有select,pselect,poll,epoll

  • 在Linux的缓存IO机制中,操作系统会将IO的数据缓存在文件系统的页缓存(page cache)。也就是说,数据会先被拷贝到操作系统内核的缓冲区中,然后才会从操作系统内核的缓存区拷贝到应用程序的地址空间中

![[Pasted image 20250815160249.png]]

select

  • select存在三个问题
    • 每次调用select,都需要把被监控的fds集合从用户态空间拷贝到内核态空间
    • 能监听端口的数量有限,单个进程所能打开的最大连接数由FD_SETSIZE宏定义
    • 被监控的fds集合中,只要有一个有数据可读,整个socket集合就会被遍历一次调用skpoll函数收集可读事件

![[1755245325283-349279b4-9119-11eb-85d0-1278b449b310.gif]]

poll

  • 针对select遗留的三个问题中(问题(2)是fd限制问题,问题(1)和(3)则是性能问题)
  • poll只是使用pollfd结构而不是select的fd_set结构,这就解决了select的问题(2)fds集合大小1024限制问题

epoll

  • 红黑树

![[1755245323731-346e30f4-9119-11eb-bb4a-4a238cf0c417.gif]]

二叉树

![[Pasted image 20250815174938.png]]

![[Pasted image 20250815175425.png]]

![[Pasted image 20250815181924.png]]

AVL树 - 平衡因子

![[Pasted image 20250815181940.png]]

![[Pasted image 20250815183433.png]]

红黑树

  • 理解左旋右旋,实现插入

![[Pasted image 20250815173105.png]]

![[Pasted image 20250815174129.png]]

文档链接说明

  • 参考47
    (99+ 封私信 / 57 条消息) IO多路复用——深入浅出理解select、poll、epoll的实现 - 知乎

  • 参考48
    5分钟学二叉搜索树(手机动画版)_哔哩哔哩_bilibili
    二叉搜索树的删除操作(手机动画版)_哔哩哔哩_bilibili

  • 参考49
    红黑树的旋转操作_哔哩哔哩_bilibili
    红黑树的插入算法_哔哩哔哩_bilibili

http://www.xdnf.cn/news/1307341.html

相关文章:

  • 智能工厂生产监控大屏-vue纯前端静态页面练习
  • PowerShell 格式化系统完全掌握(下):自定义列/格式字符串/对齐与宽度 + 实战模板
  • System V通信机制
  • Docker之安装部署——(1)配置国内docker镜像源
  • 【Twincat3】IO的SCAN 不可选中,SCAN中后扫描不到设备
  • 代码随想录二刷之“字符串”~GO
  • 嵌入式开发学习———Linux环境下网络编程学习(二)
  • 科普:Pygame 中,`pg.Surface` v.s. `screen`
  • 电工的基础知识以及仪器的使用
  • 浏览器面试题及详细答案 88道(45-55)
  • 吉他和弦学习:从音程基石到流畅弹奏
  • 机器学习——PCA(主成分分析)降维
  • MySQL快速恢复数据的N种方案完全教程
  • JavaWeb开发_Day12
  • 云原生俱乐部-杂谈2
  • UI-TARS-Desktop 深度解析:下一代智能自动化桌面平台
  • 数据处理与统计分析 —— numpy入门
  • 《Attention-driven GUI Grounding》论文精读笔记
  • 【Spring Cloud 微服务】1.Hystrix断路器
  • 【LeetCode 热题 100】55. 跳跃游戏
  • @mcp.tool如何从函数定义映射到llm系统输入
  • 如何回答研究过MQ的源码吗
  • 【121页PPT】智慧方案智慧综合体智能化设计方案(附下载方式)
  • [优选算法专题二滑动窗口——长度最小的子数组]
  • Effective C++ 条款42:了解 typename 的双重含义
  • AutoSar AP平台中EM,CM,SM,PHM,LT等AP基础软件都有宿主进程吗
  • Lecture 10: Concurrency 3
  • linux-数据链路层
  • C语言笔记6:C高级 part1
  • 【160页PPT】机械行业数字化生产供应链产品解决方案(附下载方式)