3

プログラムを書きました

#include<iostream>
using namespace std;
int n;
int main(int argc, char *argv[])
{
  std::cout << "Before reading from cin" << std::endl;

   // Below reading from cin should be executed within stipulated time
   bool b=std::cin >> n;
   if (b)
      std::cout << "input is integer for n and it's correct" << std::endl;
   else
      std::cout << "Either n is not integer or no input for n" << std::endl;
  return 0;
}

ここで std::cin ステートメントは、コンソールからの入力を待機し、何らかの入力を行って Enter キーを押すまでスリープ モードになります。

std::cin ステートメントが 10 秒後にタイムアウトになるようにしたい (ユーザーが 10 秒の間にデータを入力しない場合、コンパイラは std::cin ステートメントの下にあるプログラムの次のステートメントの実行を開始します。

マルチスレッドメカニズムを使用して解決できます。以下は私のコードです:

#include<unistd.h>
#include<stdlib.h>
#include<pthread.h>

#include<iostream>
using namespace std;
void *thread_function(void *arg);
int input_value;

int main(int argc, char *argv[])
{
    int res;
    pthread_t a_thread;
    void *thread_result;
    res=pthread_create(&a_thread,NULL,thread_function,NULL);
    if(res!=0){
            perror("Thread creation error");
            exit(EXIT_FAILURE);
    }
    //sleep(10);
    cout<<"cancelling thread"<<endl;
    res=pthread_cancel(a_thread);

    cout<<"input value="<<input_value<<endl;
    exit(EXIT_SUCCESS);
 }
 void *thread_function(void *arg)
 {
    int res;
    res=pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL);
    if(res!=0){
            perror("Unable to set pthread to cancel enbable state");
            exit(EXIT_FAILURE);
    }
    cin>>input_value;
    pthread_exit(&input_value);
 }

しかし、ここで私は問題に直面しています。スリープ機能により、ユーザーが値を入力するか、デフォルトでスリープ機能が 10 秒間スリープしないかのいずれかです。これは私が遅れているところです。

(シグナル、バイナリセマフォなど)を使用してこの問題を解決するにはどうすればよいですか。あなたの答えを私の解決策(つまりマルチスレッド)に関連付けてください。

どんな情報でも大歓迎です...

4

2 に答える 2

5

POSIX マシンを使用しているため、たとえばselect、標準入力に何かがあるかどうかを確認するために使用できます。

fd_set fds;
FD_ZERO(&fds);
FD_SET(STDIN_FILENO, &fds)

timeval timeout;
timeout.tv_sec = 5;   // A five-second timeout
timeout.tv_usec = 0;

int rc = select(STDIN_FILENO + 1, &fds, nullptr, nullptr, &timeout);
if (rc < 0)
    perror("select");
else if (rc == 0)
{
    // Timeout
}
else
{
    // There is input to be read on standard input
}

poll(Basile Starynkevitchが提案したように)を使用すると、次のようになります。

struct pollfd poller;
poller.fd = STDIN_FILENO;
poller.events = POLLIN;
poller.revents = 0;

int rc = poll(&poller, 1, 5);  // Poll one descriptor with a five second timeout
if (rc < 0)
    perror("select");
else if (rc == 0)
{
    // Timeout
}
else
{
    // There is input to be read on standard input
}
于 2013-09-03T09:54:16.320 に答える
1

これを機能させるためにいくつかのソリューションを試しましたが、現在のソリューションはかなりハックですが、select と poll を使用する他のソリューションが失敗した場合に機能します。

私のコードでは、データが利用可能であるという肯定的な結果が得られることがありますが、それstd::cin.get();以降は永久にブロックされます。std::getline(std::cin, STRINGVARIABLE);

私の解決策:

// Reset flag, initially true so that if cin blocks it will be reset
bool Reset = true;
// Create a c++11 thread to reset cin after a timeout of 100ms
std::thread ResetThread([&Reset](void){
    // This thread will wait 100ms
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
    // Then if the reset flag is still true it will reset cin by closing and opening it
    if (Reset) {
        close(STDIN_FILENO);
        // TODO: Really the output of this open call should be checked for errors
        open("/dev/null", O_RDONLY);
    }
});

// Now for the standard reading of cin:
std::string Line;
std::getline(std::cin, Line);.
// If cin was read correctly the getline command will return immediately
// This means that the reset flag will be set to false long before the thread tests it.
Reset = false;
// Finally join with the thread.
ResetThread.join();

このコードは、select または poll メソッド (私のコードにあります) と結合して、100ms ごとに新しいスレッドが作成されないようにすることができます。

明らかに、このコードの妥当性はプロジェクトの残りの部分に依存しますが、私にとってはうまくいくので、共有したいと思いました.

- 編集 -

PC 間を移動した後、このコードは期待したほど堅牢ではないようです。入力に別のブロックされたスレッドを使用することを受け入れました。ここで私の答えを参照してください。

非ブロッキング cin と長い間戦った後、それを行う唯一の堅牢な方法は、独自のスレッド内にあるようです。

実装については、こちらの私の回答を参照してください。

https://stackoverflow.com/a/39499548/1427932

于 2014-07-04T14:04:15.887 に答える