Windows平台让标准输入(stdin)的阻塞立即返回
文章目录
- 背景介绍
- 代码示例
- 版本1-基本命令处理
- 版本2-多线程命令处理,不阻塞主函数
- 版本3-即使没有用户输入,也能立即退出
背景介绍
- 在开发命令行工具或控制台应用程序时,经常需要处理用户输入。常规做法是使用标准输入(stdin)来获取用户输入的数据。常见的有C语言的getchar()、C++的std::getline()以及Windows API的ReadFile()等函数这些操作通常是阻塞的:它们会挂起调用线程,直到有数据可读或者发生某种错误。
- 然而,在某些应用场景中,可能需要在没有用户输入的情况下优雅地退出应用程序。例如,当系统需要进行紧急停止或转入其他任务时,如果输入线程因等待getchar()或std::getline()而阻塞,则无法立即响应。这种情况下,需要一种机制来使得阻塞在标准输入上的读取操作能够立即返回,从而允许程序继续执行或安全退出。
- 接下来将介绍一种实现方案,旨在解决如何让标准输入的阻塞读取在必要时能够立即返回,以提高程序的响应能力和用户体验。
代码示例
版本1-基本命令处理
std::cout << "Enter commands ('read' or 'write'). Type 'exit' to quit:" << std::endl;
std::string command;
while (std::getline(std::cin, command)) {if (command == "exit") {break; // 用户输入exit时退出循环}else if (command == "read") {std::cout << "Reading data..." << std::endl;}else if (command == "write") {std::cout << "Writing data..." << std::endl;}else {std::cout << "Unknown command. Please try 'read' or 'write'." << std::endl;}
}
版本2-多线程命令处理,不阻塞主函数
std::atomic_bool keep_running = true; // 控制线程运行的原子标志
// 创建一个处理输入的线程
std::thread input_thread([&]() {std::cout << "Enter commands ('read' or 'write'). Type 'exit' to quit:" << std::endl;std::string command;// 循环读取命令,直到收到停止信号while (keep_running && std::getline(std::cin, command)) {if (command == "exit") {keep_running = false; // 设置标志以终止循环break;}else if (command == "read") {std::cout << "Reading data..." << std::endl;}else if (command == "write") {std::cout << "Writing data..." << std::endl;}else {std::cout << "Unknown command. Please try 'read' or 'write'." << std::endl;}}});std::this_thread::sleep_for(std::chrono::seconds(10)); // 模拟等待一段时间或等待其他事件触发
keep_running = false; // 通知线程停止
input_thread.join(); // 等待线程完成
- 相较于版本1,版本2通过增加多线程处理避免了主函数的阻塞,并使用了原子标志位以便用户可以控制何时退出线程。但仍存在不足,由于输入线程依赖于 std::getline 的阻塞性质,它必须等到接收到用户输入后才能检查退出条件,因此程序的完全退出还需要依赖于用户输入,用户不输入任何内容,即使修改了标志位也无法让线程退出。
版本3-即使没有用户输入,也能立即退出
// 使用原子标志来控制线程是否应该继续运行。
std::atomic_bool keep_running = true;
// 获取标准输入的句柄。
HANDLE stdin_handle = GetStdHandle(STD_INPUT_HANDLE);// 创建一个处理输入的线程。
std::thread input_thread([&]() {std::cout << "Enter commands ('read' or 'write'). Type 'exit' to quit:" << std::endl;// 循环读取命令,直到收到停止信号。while (keep_running) {char buffer[256] = { 0 };DWORD bytes_read = 0;// 阻塞地从标准输入读取数据。if (ReadFile(stdin_handle, buffer, sizeof(buffer) - 1, &bytes_read, nullptr)) {buffer[bytes_read] = '\0'; // 确保字符串是以null终止的。std::string command(buffer);// 解析命令并执行相应操作。if (command == "exit") {keep_running = false; // 设置标志以终止循环。break;}else if (command == "read") {std::cout << "Reading data..." << std::endl;}else if (command == "write") {std::cout << "Writing data..." << std::endl;}else {std::cout << "Unknown command. Please try 'read' or 'write'." << std::endl;}}else {// 如果ReadFile失败,则输出失败消息。// 此处假设失败是因为主动取消ReadFile。std::cout << "ReadFile failure, because we want it exit." << std::endl;}}});// 主线程等待一段时间或等待其他事件触发。
std::this_thread::sleep_for(std::chrono::seconds(10));
// 通知输入线程停止。
keep_running = false;
// 取消所有挂起的I/O操作,以确保ReadFile可以退出。
CancelIoEx(stdin_handle, nullptr);
// 等待输入线程完成。
input_thread.join();
- 在版本3中,引入了 CancelIoEx 函数,这个函数用于取消指定文件句柄上所有未完成的输入/输出(I/O)操作。调用 CancelIoEx 后,所有挂起的 I/O 操作会被取消,任何阻塞的 ReadFile 调用都将返回失败。这种失败的检测使我们能够在不等待用户输入的情况下让 ReadFile 从阻塞状态返回。随后,程序会检查循环条件(例如 keep_running 标志),从而实现立即终止。
- 为什么不使用 OVERLAPPED 结构和 WaitForMultipleObjects:
- 同步属性的标准输入:标准输入(stdin)的句柄在大多数情况下是同步的,并且不支持真正的异步操作。尽管可以采用 OVERLAPPED 结构来异步读取,实际上 ReadFile 仍然表现为阻塞调用,这意味着无法通过事件来判断其可读状态。
- 简单性与需求满足:当前使用同步阻塞调用已足够满足我们的需求,即能够实现快速退出。这种同步调用方法在逻辑上更加简单直接。
相关文章:
Windows平台让标准输入(stdin)的阻塞立即返回
文章目录 背景介绍代码示例版本1-基本命令处理版本2-多线程命令处理,不阻塞主函数版本3-即使没有用户输入,也能立即退出 背景介绍 在开发命令行工具或控制台应用程序时,经常需要处理用户输入。常规做法是使用标准输入(stdin&…...
Spring中的Aware接口
Spring中的Aware接口 Aware接口介绍 Aware是Spring中的接口,它的作用是可以让Bean获取到运行环境的相关信息。比如获取到上下文、Bean在容器中的名称等。 Spring中提供了很多Aware接口的子类,具体如下: 常用接口的作用如下: …...
FFmpeg滤镜完整列表
FFmpeg滤镜完整列表 滤镜名称 用途 acompressor 压缩音频信号,当输入信号超过某个预设阈值时,压缩器就会开始工作。该滤镜使音量大的部分变得不那么响亮,而音量小的部分相对变得响亮,这样就可以使整体听起来更加均衡,常用于音乐…...
深入探索Python基础:两个至关重要的函数
新书上架~👇全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我👆,收藏下次不迷路┗|`O′|┛ 嗷~~ 目录 一、初学者的基石:print与input函数 二、类型转换:从字符串到浮点数…...
探索集合python(Set)的神秘面纱:它与字典有何不同?
新书上架~👇全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我👆,收藏下次不迷路┗|`O′|┛ 嗷~~ 目录 一、集合(Set)与字典(Dictionary)的初识 1. …...
火山引擎“奇袭”阿里云
图片|电影《美国队长3》剧照 ©自象限原创 作者丨程心 编辑丨罗辑 大模型价格战,已经不是什么新闻。 从OpenAI发布GPT-4o,将API价格下调50%,并宣布面向普通用户免费开始,就标志着大模型的竞争从性能进入到了成本…...
牛客网刷题 | BC94 反向输出一个四位数
目前主要分为三个专栏,后续还会添加: 专栏如下: C语言刷题解析 C语言系列文章 我的成长经历 感谢阅读! 初来乍到,如有错误请指出,感谢! 描述 将一个四位数&…...
记一次MySQL执行修改语句超时问题
异常问题 原因分析 这个问题发生在开发环境,怀疑是提交事务时终止项目运行,没有提交该事务,造成死锁 调试该事务时时间太长,为什么说有这个原因呢,因为通过查找日志显示 The client was disconnected by the server …...
linux fork()函数调用原理
在Linux中,fork函数用于创建一个新的进程,该进程是调用进程的子进程。fork函数的实现涉及用户态和内核态之间的交互。下面我将详细说明fork函数在代码流程中的原理和用户态与内核态的交互过程。 用户态调用fork函数: 用户程序调用fork函数,该函数是libc库提供的一个封装函数…...
【电控笔记5.9】编码器脉冲计算速度MT法
总结 编码器的脉冲计算速度可以使用多种方法,其中一种常用的方法是“MT法” (Measuring Time Method),即测量时间法。该方法通过测量编码器脉冲间的时间来计算速度。这种方法在高精度速度测量中非常有效,特别是在速度较低时。 MT法计算速度的基本原理 MT法的基本原理是通过…...
go-zero 实战(4)
中间件 在 userapi 项目中引入中间件。go项目中的中间可以处理请求之前和之后的逻辑。 1. 在 userapi/internal目录先创建 middlewares目录,并创建 user.go文件 package middlewaresimport ("github.com/zeromicro/go-zero/core/logx""net/http&q…...
go语言泛型Generic最佳实践 --- slices包
在go的内置包slices中, 所有的函数函数都使用了泛型, 各种各样的泛型, 可以说这个包绝对是go语言泛型学习的最佳实践之一! 来,先来瞄一眼,看看这个slices包里面的函数原型定义: func BinarySe…...
【神经网络结构可视化】使用 Visualkeras 可视化 Keras / TensorFlow 神经网络结构
文章目录 Visualkeras介绍下载安装代码示例1、导入必要的库2、创建VGG16神经网络模型3、可视化神经网络结构4、完整代码5、使用教程 可视化自己创建的神经网络结构1、导入要的库2、创建自己的神经网络模型3、可视化神经网络结构图4、完整代码 Visualkeras介绍 Visualkeras是一…...
nvm安装nodejs/npm/nvm笔记
1 安装nvm, 指定路径nvm路径: D:\Program_Files\nvm\nvm指定路径nodejs 路径: D:\Program_Files\nvm\nodejs 2 进入nvm安装路径找到settings.xml文件,追加2行,设置镜像 node_mirror: https://npmmirror.com/mirrors/node/ npm_mirror: ht…...
微信小程序源码-基于Java后端的小区租拼车管理信息系统毕业设计(附源码+演示录像+LW)
大家好!我是程序员一帆,感谢您阅读本文,欢迎一键三连哦。 💞当前专栏:微信小程序毕业设计 精彩专栏推荐👇🏻👇🏻👇🏻 🎀 Python毕业设…...
嵌入式进阶——LED呼吸灯(PWM)
🎬 秋野酱:《个人主页》 🔥 个人专栏:《Java专栏》《Python专栏》 ⛺️心若有所向往,何惧道阻且长 文章目录 PWM基础概念STC8H芯片PWMA应用PWM配置详解占空比 PWM基础概念 PWM全称是脉宽调制(Pulse Width Modulation)…...
一文读懂:http免费升级https
背景: 随着现在全民网络安全意识的日益提升,各个网站需要实现的https数量也随之提升,那么如何将原本网站的http访问方式升级为https呢? 该内容为如何免费将网站的http访问升级为https访问 论https的加密逻辑: 步骤 …...
算法刷题笔记 高精度除法(C++实现)
文章目录 题目描述求解思路实现代码 题目描述 给定两个非负整数(不含前导0)A,B,请你计算 A/B 的商和余数。 输入格式 共两行,第一行包含整数A,第二行包含整数B。 输出格式 共两行,第一行输…...
按月爬取天气数据可视化展示
从天气网分析,可以查询每个月的天气情况,这里按照url规则,传入年月,获取数据,最后进行可视化展示,最终效果: 下面是获取过程: 第一步: import requestsdef get_weather(month):url = f"https://lishi.tianqi.com/nanning/{month}.html"response = reques…...
VMware安装Ubuntu系统(超详细)
一.Ubuntu官网下载镜像 Ubuntu官网:Enterprise Open Source and Linux | Ubuntu 二.安装Ubuntu系统 选择文件->创建虚拟机新建虚拟机(ControlN),这里直接选择典型即可 选择稍后安装系统 选择linux Ubuntu 64位 填写虚拟机名称…...
智能在线客服平台:数字化时代企业连接用户的 AI 中枢
随着互联网技术的飞速发展,消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁,不仅优化了客户体验,还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用,并…...
视频字幕质量评估的大规模细粒度基准
大家读完觉得有帮助记得关注和点赞!!! 摘要 视频字幕在文本到视频生成任务中起着至关重要的作用,因为它们的质量直接影响所生成视频的语义连贯性和视觉保真度。尽管大型视觉-语言模型(VLMs)在字幕生成方面…...
uniapp微信小程序视频实时流+pc端预览方案
方案类型技术实现是否免费优点缺点适用场景延迟范围开发复杂度WebSocket图片帧定时拍照Base64传输✅ 完全免费无需服务器 纯前端实现高延迟高流量 帧率极低个人demo测试 超低频监控500ms-2s⭐⭐RTMP推流TRTC/即构SDK推流❌ 付费方案 (部分有免费额度&#x…...
Redis数据倾斜问题解决
Redis 数据倾斜问题解析与解决方案 什么是 Redis 数据倾斜 Redis 数据倾斜指的是在 Redis 集群中,部分节点存储的数据量或访问量远高于其他节点,导致这些节点负载过高,影响整体性能。 数据倾斜的主要表现 部分节点内存使用率远高于其他节…...
Angular微前端架构:Module Federation + ngx-build-plus (Webpack)
以下是一个完整的 Angular 微前端示例,其中使用的是 Module Federation 和 npx-build-plus 实现了主应用(Shell)与子应用(Remote)的集成。 🛠️ 项目结构 angular-mf/ ├── shell-app/ # 主应用&…...
【MATLAB代码】基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),附源代码|订阅专栏后可直接查看
文章所述的代码实现了基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),针对传感器观测数据中存在的脉冲型异常噪声问题,通过非线性加权机制提升滤波器的抗干扰能力。代码通过对比传统KF与MCC-KF在含异常值场景下的表现,验证了后者在状态估计鲁棒性方面的显著优…...
Spring Boot + MyBatis 集成支付宝支付流程
Spring Boot MyBatis 集成支付宝支付流程 核心流程 商户系统生成订单调用支付宝创建预支付订单用户跳转支付宝完成支付支付宝异步通知支付结果商户处理支付结果更新订单状态支付宝同步跳转回商户页面 代码实现示例(电脑网站支付) 1. 添加依赖 <!…...
AD学习(3)
1 PCB封装元素组成及简单的PCB封装创建 封装的组成部分: (1)PCB焊盘:表层的铜 ,top层的铜 (2)管脚序号:用来关联原理图中的管脚的序号,原理图的序号需要和PCB封装一一…...
PydanticAI快速入门示例
参考链接:https://ai.pydantic.dev/#why-use-pydanticai 示例代码 from pydantic_ai import Agent from pydantic_ai.models.openai import OpenAIModel from pydantic_ai.providers.openai import OpenAIProvider# 配置使用阿里云通义千问模型 model OpenAIMode…...
Redis上篇--知识点总结
Redis上篇–解析 本文大部分知识整理自网上,在正文结束后都会附上参考地址。如果想要深入或者详细学习可以通过文末链接跳转学习。 1. 基本介绍 Redis 是一个开源的、高性能的 内存键值数据库,Redis 的键值对中的 key 就是字符串对象,而 val…...
