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

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-多线程命令处理&#xff0c;不阻塞主函数版本3-即使没有用户输入&#xff0c;也能立即退出 背景介绍 在开发命令行工具或控制台应用程序时&#xff0c;经常需要处理用户输入。常规做法是使用标准输入&#xff08;stdin&…...

Spring中的Aware接口

Spring中的Aware接口 Aware接口介绍 Aware是Spring中的接口&#xff0c;它的作用是可以让Bean获取到运行环境的相关信息。比如获取到上下文、Bean在容器中的名称等。 Spring中提供了很多Aware接口的子类&#xff0c;具体如下&#xff1a; 常用接口的作用如下&#xff1a; …...

FFmpeg滤镜完整列表

FFmpeg滤镜完整列表 滤镜名称 用途 acompressor 压缩音频信号,当输入信号超过某个预设阈值时&#xff0c;压缩器就会开始工作。该滤镜使音量大的部分变得不那么响亮&#xff0c;而音量小的部分相对变得响亮&#xff0c;这样就可以使整体听起来更加均衡&#xff0c;常用于音乐…...

深入探索Python基础:两个至关重要的函数

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、初学者的基石&#xff1a;print与input函数 二、类型转换&#xff1a;从字符串到浮点数…...

探索集合python(Set)的神秘面纱:它与字典有何不同?

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、集合&#xff08;Set&#xff09;与字典&#xff08;Dictionary&#xff09;的初识 1. …...

火山引擎“奇袭”阿里云

图片&#xff5c;电影《美国队长3》剧照 ©自象限原创 作者丨程心 编辑丨罗辑 大模型价格战&#xff0c;已经不是什么新闻。 从OpenAI发布GPT-4o&#xff0c;将API价格下调50%&#xff0c;并宣布面向普通用户免费开始&#xff0c;就标志着大模型的竞争从性能进入到了成本…...

牛客网刷题 | BC94 反向输出一个四位数

目前主要分为三个专栏&#xff0c;后续还会添加&#xff1a; 专栏如下&#xff1a; C语言刷题解析 C语言系列文章 我的成长经历 感谢阅读&#xff01; 初来乍到&#xff0c;如有错误请指出&#xff0c;感谢&#xff01; 描述 将一个四位数&…...

记一次MySQL执行修改语句超时问题

异常问题 原因分析 这个问题发生在开发环境&#xff0c;怀疑是提交事务时终止项目运行&#xff0c;没有提交该事务&#xff0c;造成死锁 调试该事务时时间太长&#xff0c;为什么说有这个原因呢&#xff0c;因为通过查找日志显示 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目录&#xff0c;并创建 user.go文件 package middlewaresimport ("github.com/zeromicro/go-zero/core/logx""net/http&q…...

go语言泛型Generic最佳实践 --- slices包

在go的内置包slices中&#xff0c; 所有的函数函数都使用了泛型&#xff0c; 各种各样的泛型&#xff0c; 可以说这个包绝对是go语言泛型学习的最佳实践之一&#xff01; 来&#xff0c;先来瞄一眼&#xff0c;看看这个slices包里面的函数原型定义&#xff1a; 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路径&#xff1a; D:\Program_Files\nvm\nvm指定路径nodejs 路径&#xff1a; D:\Program_Files\nvm\nodejs 2 进入nvm安装路径找到settings.xml文件,追加2行&#xff0c;设置镜像 node_mirror: https://npmmirror.com/mirrors/node/ npm_mirror: ht…...

微信小程序源码-基于Java后端的小区租拼车管理信息系统毕业设计(附源码+演示录像+LW)

大家好&#xff01;我是程序员一帆&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f49e;当前专栏&#xff1a;微信小程序毕业设计 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f380; Python毕业设…...

嵌入式进阶——LED呼吸灯(PWM)

&#x1f3ac; 秋野酱&#xff1a;《个人主页》 &#x1f525; 个人专栏:《Java专栏》《Python专栏》 ⛺️心若有所向往,何惧道阻且长 文章目录 PWM基础概念STC8H芯片PWMA应用PWM配置详解占空比 PWM基础概念 PWM全称是脉宽调制&#xff08;Pulse Width Modulation&#xff09…...

一文读懂:http免费升级https

背景&#xff1a; 随着现在全民网络安全意识的日益提升&#xff0c;各个网站需要实现的https数量也随之提升&#xff0c;那么如何将原本网站的http访问方式升级为https呢&#xff1f; 该内容为如何免费将网站的http访问升级为https访问 论https的加密逻辑&#xff1a; 步骤 …...

算法刷题笔记 高精度除法(C++实现)

文章目录 题目描述求解思路实现代码 题目描述 给定两个非负整数&#xff08;不含前导0&#xff09;A&#xff0c;B&#xff0c;请你计算 A/B 的商和余数。 输入格式 共两行&#xff0c;第一行包含整数A&#xff0c;第二行包含整数B。 输出格式 共两行&#xff0c;第一行输…...

按月爬取天气数据可视化展示

从天气网分析,可以查询每个月的天气情况,这里按照url规则,传入年月,获取数据,最后进行可视化展示,最终效果: 下面是获取过程: 第一步: import requestsdef get_weather(month):url = f"https://lishi.tianqi.com/nanning/{month}.html"response = reques…...

VMware安装Ubuntu系统(超详细)

一.Ubuntu官网下载镜像 Ubuntu官网&#xff1a;Enterprise Open Source and Linux | Ubuntu 二.安装Ubuntu系统 选择文件->创建虚拟机新建虚拟机&#xff08;ControlN&#xff09;&#xff0c;这里直接选择典型即可 选择稍后安装系统 选择linux Ubuntu 64位 填写虚拟机名称…...

模型参数、模型存储精度、参数与显存

模型参数量衡量单位 M&#xff1a;百万&#xff08;Million&#xff09; B&#xff1a;十亿&#xff08;Billion&#xff09; 1 B 1000 M 1B 1000M 1B1000M 参数存储精度 模型参数是固定的&#xff0c;但是一个参数所表示多少字节不一定&#xff0c;需要看这个参数以什么…...

day52 ResNet18 CBAM

在深度学习的旅程中&#xff0c;我们不断探索如何提升模型的性能。今天&#xff0c;我将分享我在 ResNet18 模型中插入 CBAM&#xff08;Convolutional Block Attention Module&#xff09;模块&#xff0c;并采用分阶段微调策略的实践过程。通过这个过程&#xff0c;我不仅提升…...

Mybatis逆向工程,动态创建实体类、条件扩展类、Mapper接口、Mapper.xml映射文件

今天呢&#xff0c;博主的学习进度也是步入了Java Mybatis 框架&#xff0c;目前正在逐步杨帆旗航。 那么接下来就给大家出一期有关 Mybatis 逆向工程的教学&#xff0c;希望能对大家有所帮助&#xff0c;也特别欢迎大家指点不足之处&#xff0c;小生很乐意接受正确的建议&…...

【Go】3、Go语言进阶与依赖管理

前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课&#xff0c;做自我学习总结整理。 Go语言并发编程 Go语言原生支持并发编程&#xff0c;它的核心机制是 Goroutine 协程、Channel 通道&#xff0c;并基于CSP&#xff08;Communicating Sequential Processes&#xff0…...

linux 下常用变更-8

1、删除普通用户 查询用户初始UID和GIDls -l /home/ ###家目录中查看UID cat /etc/group ###此文件查看GID删除用户1.编辑文件 /etc/passwd 找到对应的行&#xff0c;YW343:x:0:0::/home/YW343:/bin/bash 2.将标红的位置修改为用户对应初始UID和GID&#xff1a; YW3…...

【决胜公务员考试】求职OMG——见面课测验1

2025最新版&#xff01;&#xff01;&#xff01;6.8截至答题&#xff0c;大家注意呀&#xff01; 博主码字不易点个关注吧,祝期末顺利~~ 1.单选题(2分) 下列说法错误的是:&#xff08; B &#xff09; A.选调生属于公务员系统 B.公务员属于事业编 C.选调生有基层锻炼的要求 D…...

【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)

升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点&#xff0c;但无自动故障转移能力&#xff0c;Master宕机后需人工切换&#xff0c;期间消息可能无法读取。Slave仅存储数据&#xff0c;无法主动升级为Master响应请求&#xff…...

JDK 17 新特性

#JDK 17 新特性 /**************** 文本块 *****************/ python/scala中早就支持&#xff0c;不稀奇 String json “”" { “name”: “Java”, “version”: 17 } “”"; /**************** Switch 语句 -> 表达式 *****************/ 挺好的&#xff…...

全志A40i android7.1 调试信息打印串口由uart0改为uart3

一&#xff0c;概述 1. 目的 将调试信息打印串口由uart0改为uart3。 2. 版本信息 Uboot版本&#xff1a;2014.07&#xff1b; Kernel版本&#xff1a;Linux-3.10&#xff1b; 二&#xff0c;Uboot 1. sys_config.fex改动 使能uart3(TX:PH00 RX:PH01)&#xff0c;并让boo…...

SQL慢可能是触发了ring buffer

简介 最近在进行 postgresql 性能排查的时候,发现 PG 在某一个时间并行执行的 SQL 变得特别慢。最后通过监控监观察到并行发起得时间 buffers_alloc 就急速上升,且低水位伴随在整个慢 SQL,一直是 buferIO 的等待事件,此时也没有其他会话的争抢。SQL 虽然不是高效 SQL ,但…...