在 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...
但是我还是不知道接下来要做什么...
规范的 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!";
}
}
您想要做的是从 stdin
读取非阻塞(异步),超时时间为 10 秒。这不是太难,但可能涉及许多新概念,具体取决于您当前的水平。
这里的关键概念是 cin >> password;
是一个 阻塞 调用,也就是说,在它完成之前,控制不会在此代码中进一步流动。所以我们需要通过某种方式使其成为非阻塞的,或者保持阻塞状态并在超时到期时跳出它。
根据系统的设计要求和约束,有一些常见的实现。每种实现都因 OS 而异,但技术非常相似。
1.异步:带超时的 STDIN
这种方式在网络编程中很常用,可以扩展到其他形式的输入如当前案例。
- 将标准输入 (STDIN) 句柄 (handle = 0) 放入 'watch-list'.
- 在监视列表中设置超时。
- 只要 STDIN 发生变化,就进行处理。
- 超时过后,检查我们处理的内容是否完成了工作。
在Linux(以及许多其他 Unix 风格)中,监视列表可以使用 FD_SET
和 select
系统调用来处理。在 Windows 中,您将需要使用 WaitForMultipleEvents
。
我不确定我是否可以出于这个问题的目的准确地解释这些概念。作为参考,另一个问题有一些完全相同的代码指针是 here.
2。同步:带中断的多线程
这是一种常用技术,用于我们需要细粒度事件调度程序/计时器的情况。
- 创建两个线程,
A
和 B
。
A
将等待指示的超时时间。
B
将等待阻塞读取
- 如果
A
在 B
完成之前终止(超时),A
会发出信号 B
并且 B
决定下一步做什么(终止,重复一条消息等)
- 如果
B
读取了密码并且没有问题,B
向 A
发出信号并要求它死掉。
实现相同目的的另一种方法是使 OS 中断线程 B
如 comments 中所述。
3。同步:轮询
这用于我们不需要对时间进行过多细粒度控制的情况。
- 使用非阻塞读取检查输入中是否有任何内容 (
kbhit()
)
- 如果有none,超时还有剩余时间,等待更小的时间
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 OUT\n";
else
if (password == "password123")
std::cout << "Correct";
else
std::cout << "Worng";
return 0;
}
但是如果你检查一下你会发现它一直等到 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 OUT\n";
else
if (password == "password123")
std::cout << "Correct";
else
std::cout << "Worng";
return 0;
}
我想要一个用户有 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...
但是我还是不知道接下来要做什么...
规范的 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!";
}
}
您想要做的是从 stdin
读取非阻塞(异步),超时时间为 10 秒。这不是太难,但可能涉及许多新概念,具体取决于您当前的水平。
这里的关键概念是 cin >> password;
是一个 阻塞 调用,也就是说,在它完成之前,控制不会在此代码中进一步流动。所以我们需要通过某种方式使其成为非阻塞的,或者保持阻塞状态并在超时到期时跳出它。
根据系统的设计要求和约束,有一些常见的实现。每种实现都因 OS 而异,但技术非常相似。
1.异步:带超时的 STDIN 这种方式在网络编程中很常用,可以扩展到其他形式的输入如当前案例。
- 将标准输入 (STDIN) 句柄 (handle = 0) 放入 'watch-list'.
- 在监视列表中设置超时。
- 只要 STDIN 发生变化,就进行处理。
- 超时过后,检查我们处理的内容是否完成了工作。
在Linux(以及许多其他 Unix 风格)中,监视列表可以使用 FD_SET
和 select
系统调用来处理。在 Windows 中,您将需要使用 WaitForMultipleEvents
。
我不确定我是否可以出于这个问题的目的准确地解释这些概念。作为参考,另一个问题有一些完全相同的代码指针是 here.
2。同步:带中断的多线程 这是一种常用技术,用于我们需要细粒度事件调度程序/计时器的情况。
- 创建两个线程,
A
和B
。 A
将等待指示的超时时间。B
将等待阻塞读取- 如果
A
在B
完成之前终止(超时),A
会发出信号B
并且B
决定下一步做什么(终止,重复一条消息等) - 如果
B
读取了密码并且没有问题,B
向A
发出信号并要求它死掉。
实现相同目的的另一种方法是使 OS 中断线程 B
如 comments 中所述。
3。同步:轮询 这用于我们不需要对时间进行过多细粒度控制的情况。
- 使用非阻塞读取检查输入中是否有任何内容 (
kbhit()
) - 如果有none,超时还有剩余时间,等待更小的时间
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 OUT\n";
else
if (password == "password123")
std::cout << "Correct";
else
std::cout << "Worng";
return 0;
}
但是如果你检查一下你会发现它一直等到 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 OUT\n";
else
if (password == "password123")
std::cout << "Correct";
else
std::cout << "Worng";
return 0;
}