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位 填写虚拟机名称…...
CVPR 2023反无人机数据集实战:用ModelScope上的开源模型快速上手目标检测
CVPR 2023反无人机数据集实战:用ModelScope上的开源模型快速上手目标检测无人机技术的普及带来了新的安全挑战,从隐私侵犯到关键设施威胁,反无人机技术正成为计算机视觉领域的热点。CVPR 2023反无人机竞赛提供的开源数据集和基线模型…...
QMCDecode终极指南:3步解锁QQ音乐加密格式,实现跨平台音乐自由
QMCDecode终极指南:3步解锁QQ音乐加密格式,实现跨平台音乐自由 【免费下载链接】QMCDecode QQ音乐QMC格式转换为普通格式(qmcflac转flac,qmc0,qmc3转mp3, mflac,mflac0等转flac),仅支持macOS,可自动识别到QQ音乐下载目…...
为什么软件开发偏爱 Linux?深度剖析 Linux 相较于 Windows 的核心优势
引言 在软件开发的世界里,一个有趣的现象是:无论是大型互联网公司的服务器集群,还是资深程序员的个人开发机,Linux 操作系统的身影无处不在。与之形成鲜明对比的是,尽管 Windows 在个人消费市场占据绝对主导地位&…...
告别枯燥理论!用Unity脚本生命周期与预制体玩转一个“会变身的敌人”
用Unity打造会变身的敌人:脚本生命周期与预制体的实战应用在游戏开发中,敌人AI的行为设计往往是新手开发者最感兴趣也最容易感到困惑的部分。Unity的脚本生命周期和预制体系统为这类需求提供了强大支持,但教科书式的讲解常常让学习者陷入枯燥…...
DIY智能USB充电器:基于电流检测与双稳态继电器的零功耗节能方案
1. 项目概述:打造一款智能、节能的USB手机充电器作为一名电子爱好者,我经常折腾各种电源项目。市面上很多手机充电器,包括一些原装货,都存在一个通病:手机充满电后,充电器依然插在插座上,内部电…...
3分钟掌握Topit:Mac窗口置顶终极指南,让多任务处理效率翻倍!
3分钟掌握Topit:Mac窗口置顶终极指南,让多任务处理效率翻倍! 【免费下载链接】Topit Pin any window to the top of your screen / 在Mac上将你的任何窗口强制置顶 项目地址: https://gitcode.com/gh_mirrors/to/Topit 你是否曾经在Ma…...
网盘直链下载助手:九大主流平台高速下载终极指南
网盘直链下载助手:九大主流平台高速下载终极指南 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 ,支持 百度网盘 / 阿里云盘 / 中国移动云盘 / 天翼云盘 …...
QKeyMapper终极指南:Windows上最强大的开源按键映射工具
QKeyMapper终极指南:Windows上最强大的开源按键映射工具 【免费下载链接】QKeyMapper [按键映射工具] QKeyMapper,Qt开发Win10&Win11可用,不修改注册表、不需重新启动系统,可立即生效和停止。支持游戏手柄映射到键鼠ÿ…...
别再死记硬背公式了!用UE5的Lerp节点玩转材质混合(附灰度图实战案例)
别再死记硬背公式了!用UE5的Lerp节点玩转材质混合(附灰度图实战案例)在游戏开发中,材质混合是创造丰富视觉效果的关键技术。对于Unreal Engine 5的初学者来说,LinearInterpolate(简称Lerp)节点可…...
Arduino打地鼠游戏机:从74HC595矩阵驱动到状态机编程全解析
1. 项目概述:用Arduino复刻经典打地鼠游戏作为一个电子爱好者,我总想把手头的Arduino和各种元器件玩出点新花样。这次,我决定挑战一个经典街机项目——电子打地鼠。市面上虽然有现成的玩具,但自己从头设计、画板、编程,…...
