C++でタイムアウト機能を実装したいと思います。
ユーザーが2秒以内に値を入力しない場合、プログラムはタイムアウトステートメントを表示し、もう一度入力を求める必要があります。
EX(出力画面):
Timer=0;
Please enter the input: //if input is not given within 2 seconds then
Time-out: 2 seconds
Timer again set to 0
Please enter the input: //if input is not given within 2 seconds then
Time-out: 2 seconds
Timer again set to 0
Please enter the input:22
Data accepted
Terminate the program`
コード:
#include<iostream>
#include<time.h>
using namespace std;
int main()
{
clock_t endwait;
endwait = 2000 ;
cout<<endwait;
while (clock() < endwait)
{
cout<<"Please enter the input:";
}
return 0;
}
私は上記のコードに取り組んできました。ただし、これはWHILEループに入っているときにのみ発生します。必要な出力が得られるようにするにはどうすればよいですか。
#include <iostream>
#include <thread>
#include <chrono>
#include <mutex>
#include <condition_variable>
using namespace std;
condition_variable cv;
int value;
void read_value() {
cin >> value;
cv.notify_one();
}
int main()
{
cout << "Please enter the input: ";
thread th(read_value);
mutex mtx;
unique_lock<mutex> lck(mtx);
while (cv.wait_for(lck, chrono::seconds(2)) == cv_status::timeout)
{
cout << "\nTime-Out: 2 second:";
cout << "\nPlease enter the input:";
}
cout << "You entered: " << value << '\n';
th.join();
return 0;
}
出力:
Please enter the input:
Time-Out: 2 second:
Please enter the input:
Time-Out: 2 second:
Please enter the input:22
You entered: 22
この目的のために複雑なコード(マルチスレッドまたはミューテックス)を使用する必要はないと思います。以下のコードを参照してください。
#include <iostream>
#include <time.h>
#include <conio.h>
using namespace std;
int main()
{
int numInput;
clock_t start = clock();
cout << "Timer: 2 sec"<<endl;
cout << "Please enter the input: ";
while ( ! _kbhit() ) //Check for keyboard hit
{
//Check if 2 sec timer expired or not
if (((clock () - start)/ CLOCKS_PER_SEC ) >= 2)
{
cout << "\nTimeout 2 sec . . ." << endl;
cout << "Please enter the input: ";
start = clock(); //Set new timer
}
}
//Get the input here
cin >> numInput;
cout << "Data accepted: " << numInput << endl;
_getch();
return 0;
}
私はあなたの問題を解決するためにkbhit()関数を使用しました。コードは次のとおりです。-
#include <conio.h>
#include <iostream>
#include <windows.h>
using namespace std;
int main()
{
int i;
DWORD start_time, check_time;
start_time=GetTickCount();
check_time=start_time+2000;
while(!kbhit())
{
cout<<"Please enter the input:"<<endl;
while((check_time>GetTickCount()))
{
if (kbhit())
{
i=getch();
cout<<"Data accepted"<<endl;
return 0;
}
}
cout<<"Time-out: 2 seconds"<<endl;
cout<<"Timer again set to 0"<<endl;
start_time=GetTickCount();
check_time=start_time+2000;
}
return 0;
}
恐れ入りますが、I/O操作は、デフォルトで、終了するかエラーが発生するまで呼び出しプロセスをブロックするため、標準的な方法では不可能です。
入力が完了したかどうかをチェックし、必要に応じてスリープ状態になるスレッドを作成することで、回避できます。しかし、それは実際には実用的ではありません。
問題は、iostream
/FILE
sが提供する抽象化にあります。OSが「理解」しているため、そのようなソースを提供できる、基盤となるソースにアクセスできません。機能の(つまり、I/Oポーリング)。
タイムアウトが発生した後もコンソール読み取り機能が実行されているため、別のスレッドでは不十分です。
POSIXでは、シグナルを生成し、読み取りが-EINTR
で失敗するタイマーを設定できます。
Windowsでは、ReadConsoleInput
およびWaitForSingleObject
...を使用して低レベルのコンソールI/Oタイムアウトを実装できますが、独自のラインバッファリングを行う必要があります。
別のアイデアは、ReadFile
モードでOVERLAPPED
を使用し、タイムアウトで完了イベントを待機することですが、コンソールでは機能しません。 重複したIOコンソール入力用?
最後に、新しいWindowsバージョン(Vista以降)では、 CancelIoEx
を使用して、「読み取りのブロックがタイムアウトによってキャンセルされない」問題を克服できます。別のスレッドから呼び出すと、ReadFile
がトリガーされて早期に戻ります。自分でラインバッファリングを実装する必要はありません。