输入C 中的超时
Input with a timeout in C++
我想拥有一个程序,其中用户有10秒钟输入密码。如果计时器超过10秒,则该程序将显示一条消息。我当前的代码是:
#include <iostream>
#include <ctime>
#include <string>
int main(){
std::string password;
int start_s=clock();
int stop_s=clock();
if(stop_s-start_s <= 0){
std::cout << "TIME RAN OUT!";
}
std::cout << "Enter your password! n";
std::cout << "Password: ";
std::cin >> password;
std::cout << "n n";
if (password == "password123"){
std::cout << "Correct!";
} else {
std::cout << "Wrong!";
}
}
这当然不起作用...但是我不确定下一步该怎么做...
如果您需要更多详细信息,请在评论中询问。
编辑:
我刚刚意识到问题是什么...它花了时间戳记,然后迅速制作了另一个时间戳记。当发现差异时,它低于0 ...
但我仍然不知道下一步该怎么做...
您要做的是要以10秒的超时范围从stdin
读取非阻滞(异步)。这并不是太难了,但可能会根据您当前的水平涉及许多新概念。
这里的关键概念是cin >> password;
是A 阻止调用,即直到完成为止,该代码中的控制不会进一步流动。因此,我们需要以某种方式使其不受阻碍,或者在超时到期时将其阻止并脱离。
根据系统的设计要求和约束,有一些常见的实现。每个实现都不同于OS,但技术非常相似。
1。异步:与超时的stdin 这种方法通常用于网络编程中,可以扩展到其他形式的输入,例如当前情况。
- 将标准输入(stdin)句柄(句柄= 0)放入"手表列表"。
- 将暂停放在手表列表上。
- 每当stdin发生变化时,请处理。
- 超时到期后,检查我们处理的工作是否完成工作。
在Linux(以及许多其他Unix口味)中,可以使用FD_SET
和select
系统调用来处理手表列表。在Windows中,您需要使用WaitForMultipleEvents
。
我不确定我是否可以为此目的准确解释这些概念。作为参考,这里有一些代码指针的另一个问题在这里。
2。同步:多线程与中断这是一种常用技术,用于我们需要细粒度螺纹式螺旋/计时器的情况。
- 创建两个线程
A
和B
。 -
A
将在指示的超时等待。 -
B
将等待阻止读取 - 如果
A
在B
完成之前终止(Times Out),则A
信号B
和B
决定下一步该怎么做(终止,重复消息等)
)
- 如果
B
读取密码并且很好,B
信号A
并要求它死。
实现同样的方法的另一种方法是使OS中断线程B
如其中的一个注释。
3。同步:投票这是用于我们不需要过多的细粒度控制的情况。
- 检查输入中是否使用非阻滞读取(
kbhit()
)
是否有任何内容 - 如果没有,如果超时存在时间,请等待较小的时间
delta
(例如10ms
) - 如果超时已经过期并且没有更多的时间,请执行任何需要处理(消息用户,退出等) )
请注意,在这种情况下,根据delta
,该方法可能会消耗大量CPU,并且可能效率低下。例如,如果delta=10ms
如上所述,则该线程将每秒唤醒100次,并且不会有效,尤其是当用户在其键盘上未在键盘上输入字符时。
此代码使用线程进行。
#include <iostream>
#include <thread>
#include <chrono>
#include <string>
int main()
{
std::string password;
std::cout << "Enter your password! n";
std::cout << "Password: ";
//try to read a passsword in 10 seconds
std::thread t1([&]() {
std::cin >> password;
});
std::this_thread::sleep_for(std::chrono::seconds(10));
t1.detach();
//check if password was entered
if (password.empty())
std::cout << "TIME IS OUTn";
else
if (password == "password123")
std::cout << "Correct";
else
std::cout << "Worng";
return 0;
}
但是,如果您查看,即使用户在时间上输入了Passsword,也可以看到它等待10秒的末尾。因此您可以这样改进:
#include <iostream>
#include <thread>
#include <chrono>
#include <string>
int main()
{
std::string password;
std::cout << "Enter your password! n";
std::cout << "Password: ";
time_t start = time(NULL);
time_t waitTime = 10;
//try to read a passsword in 10 seconds
while (time(NULL) < start + waitTime && password.empty())
{
std::thread t1([&]() {
std::cin >> password;
});
std::this_thread::sleep_for(std::chrono::milliseconds(20));
t1.detach();
}
//check if password was entered
if (password.empty())
std::cout << "nTIME IS OUTn";
else
if (password == "password123")
std::cout << "Correct";
else
std::cout << "Worng";
return 0;
}
我最近遇到了同一问题。我从 @user1952500中找到答案,呈现有趣的方法。其中,第二个是我更容易理解的。
但是,我还没有为此找到好的代码解决方案。更一般而言,使用分离不会杀死线程,但它让独立运行("主线程之外")。这意味着线程将永远运行,直到整个代码终止为止,如果我们分离多个线程,这甚至是一个更糟糕的情况。
要使用螺纹在超时使用超时完成键盘输入,必须从另一个线程中杀死该线程。问题是:不可能仅使用C 标准库进行操作。
有必要使用依赖平台的功能。这是我对Linux的解决方案:
#include <thread>
#include <chrono>
#include <stdio.h>
#include <pthread.h>
#include <string>
std::chrono::milliseconds now_ms(){
return std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch()
);
}
int main(){
// set timeout
std::chrono::milliseconds timeout(10000);
// variable to check if the thread terminated by itself
bool thread_terminated = false;
// variable to store input
std::string answer;
// create thread
std::thread t1([&]() {
std::cin >> answer;
thread_terminated = true;
});
// get native handle
auto t_handle = t1.native_handle();
// start the thread
auto start_ts = now_ms();
t1.detach()
// check for timeout or answer received
while(this->now_ms_d() - start_ts < timeout && answer.empty()){
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
// if the thread didn't terminate, kill it
if(! thread_terminated) pthread_cancel(t_handle);
if (answer.empty()){
std::cout << "no answer received" << std::endl;
}
else{
/* do what you need to do with answer */
}
return 0;
}
对于不同的平台,您需要调用其他功能,而不是pthread_cancel(t_handle)
。
例如,在Windows上,您可以使用terminateThread。
典型的C 解决方案应该看起来像:
#include <iostream>
#include <chrono>
#include <string>
int main() {
std::string password;
std::cout << "Enter your password! n";
std::cout << "Password: ";
auto start_s = std::chrono::system_clock::now();
std::cin >> password;
auto stop_s = std::chrono::system_clock::now();
if(stop_s - start_s >= std::chrono::seconds(10)) {
std::cout << "TIME RAN OUT!";
}
else if (password == "password123") {
std::cout << "Correct!";
} else {
std::cout << "Wrong!";
}
}
- 在C++程序中输入的文本文件将不起作用,除非文本被复制和粘贴
- 2D数组来自文本输入,中间有空格
- 如何使用 < 和 > 命令获取 c++ 中的输入和输出?
- 检查输入是否不是整数或数字
- 正在尝试了解输入验证循环
- 读取文件并输入到矢量中
- C++如何通过用户输入删除列表元素
- 用c++从输入文件中读取另一行
- 读取文件的最后一行并输入到链接列表时出错
- 创建一个函数以在输入为负数或零时输出字符串.第一次执行用户定义的函数
- 如何使用用户输入在C++中正确填充2D数组
- C++MySQL C api用户输入行
- 输入到文件并输出到另一个文件,并将流文件传递给函数
- 用户定义函数中的指针和输入
- 如何在Qt 4.8中阻止/忽略/丢弃早于特定超时的用户输入事件
- 设置输入(CIN)的超时
- 输入C 中的超时
- win32 C++项目中的输入超时
- Win32 - 从标准输入读取超时
- 选择线程:超时和用户输入