bugfix> c++ > 投稿

ユーザー割り込みが到着したときにスリープを終了する方法を探しています。重要なのは出口これを行うのではなく、スリープします。スリープを中断し、ISR処理を実行して、スリープに戻ります。これが、私が解決策を見つけている理由です。

私はC ++でこのようなものを探しています-Cでの同等のものはさらに優れています:

void *timer_thread(void *dummy)
{
  while(1)
  {
    // Check if some callbacks are to be given
    // when all are given, Determine x duration to sleep
  
    try
    {
      sleep(x);
    }
    except(/* the except block should hit ONLY when an interrupt arrives, 
              that too only when sleep() is executed. It's OK to delay 
              interrupt until the sleep is beginning execution */) 
    {
      //Do something else
    }
  }
}

到着する割り込みは、ほとんどの場合、タイマースレッドがコールバックを早く行うためにスリープを減らす必要があることを示します。しかし、ユースケースに関係なく、割り込みが到着したときに何らかの方法でスリープを終了する必要があります。これを行う方法についての情報が見つかりませんでした。

PS:スリープが発生していないときに割り込みが発生した場合は、割り込みを破棄/ NOPしても問題ありません

これは、Windows 10(C/C ++)のCygwin gccv9.3.0にあります。コードを移植可能にする必要はないので、プラットフォーム固有のソリューションでも問題ありません。

この動作に似た他の解決策(sleep()と割り込みを使用しない)がある場合は、それを聞いて歓迎します。ポーリングを伴わない方法を探しています。

回答 2 件
  • 一定時間待つまたは特定のイベントでは、私はの組み合わせを使用しますstd :: mutexそしてstd :: condition_variable具体的にはstd :: condition_variable :: wait_for()タイムアウトまたは何かの合図された変更のいずれかを待つため。

    デモンストレーション用の最小限のサンプルプログラム:

    #include <atomic>
    #include <condition_variable>
    #include <iostream>
    #include <mutex>
    #include <thread>
    #include <chrono>
    using namespace std::chrono_literals;
    // a thread-shared flag to signal exit
    std::atomic<bool> exitThread = false;
    // a mutex to sync. inter-thread communication
    std::mutex mtxAlert;
    // a condition variable to signal changed data
    std::condition_variable sigAlert;
    // the data of inter-thread communication
    bool alert = false;
    void timerThread()
    {
      // the timeout for timer thread
      auto timeout = 100ms;
      // runtime loop
      while (!exitThread) {
        // lock mutex (preparation to wait in cond. var.)
        std::unique_lock<std::mutex> lock(mtxAlert);
        // unlock mutex and wait for timeout or signaled alert
        sigAlert.wait_for(lock, timeout, []() { return alert || exitThread; });
        // mutex is locked again
        // check why wait_for() exited
        if (exitThread) {
          std::cout << "Timer thread exiting...\n";
          return;
        } else if (alert) {
          std::cout << "Timer was interrupted due to alert.\n";
          alert = false;
        } else {
          std::cout << "Timer achieved time-out.\n";
        }
      }
    }
    int main()
    {
      std::thread threadWait(&timerThread);
      // wait a bit
      std::cout << "main(): Waiting 300ms...\n";
      std::this_thread::sleep_for(300ms);
      // sim. interrupt
      std::cout << "main(): Sim. interrupt.\n";
      { std::lock_guard<std::mutex> lock(mtxAlert);
        alert = true;
      }
      sigAlert.notify_all();
      // wait a bit
      std::cout << "main(): Waiting 50 ms...\n";
      std::this_thread::sleep_for(50ms);
      // sim. interrupt
      std::cout << "main(): Sim. interrupt.\n";
      { std::lock_guard<std::mutex> lock(mtxAlert);
        alert = true;
      }
      sigAlert.notify_all();
      // wait a bit
      std::cout << "main(): Waiting 50 ms...\n";
      std::this_thread::sleep_for(50ms);
      // exiting application
      exitThread = true;
      sigAlert.notify_all();
      threadWait.join();
      // done
      std::cout << "Done.\n";
    }
    
    

    出力:

    main(): Waiting 300ms...
    Timer achieved time-out.
    Timer achieved time-out.
    main(): Sim. interrupt.
    main(): Waiting 50 ms...
    Timer was interrupted due to alert.
    main(): Sim. interrupt.
    main(): Waiting 50 ms...
    Timer was interrupted due to alert.
    Timer thread exiting...
    Done.
    
    

    coliruのライブデモ


    OPはコメントごとに、このサンプルは正しくコンパイルされなかったと主張しましたcygwin。私は自分の側で試しましたが、修正したいくつかの小さな問題を確認できます。

    行方不明 #include <mutex> 追加

    の初期化 std::atomic<bool> exitThread = false; に変更されました

    std::atomic<bool> exitThread(false);
    
    

    でコンパイルしたときにこれを手に入れました g++ と同様に g++ -std=c++14 。 (のようだ -std=c++14 私のデフォルトです g++ 。)

    使うとき g++ -std=c++17 代わりに、私は何の不満も受けません。私はそれが何かと関係があると強く信じていますコピーの省略これ g++ で適用 -std=c++17 しかし、前ではありません。

    ただし、これは私のWindows10ラップトップで少しレビューしたコードを使用したサンプルセッションです。cygwin64

    $ g++ --version
    g++ (GCC) 7.4.0
    $
    
    
    $ cat >testCondVar.cc <<'EOF'
    > #include <atomic>
    > #include <condition_variable>
    > #include <iostream>
    > #include <mutex>
    > #include <thread>
    > #include <chrono>
    > using namespace std::chrono_literals;
    > 
    > // a thread-shared flag to signal exit
    > std::atomic<bool> exitThread(false);
    > 
    > // a mutex to sync. inter-thread communication
    > std::mutex mtxAlert;
    > // a condition variable to signal changed data
    > std::condition_variable sigAlert;
    > // the data of inter-thread communication
    > bool alert = false;
    > 
    > void timerThread()
    > {
    >   // the timeout for timer thread
    >   auto timeout = 100ms;
    >   // runtime loop
    >   while (!exitThread) {
    >     // lock mutex (preparation to wait in cond. var.)
    >     std::unique_lock<std::mutex> lock(mtxAlert);
    >     // unlock mutex and wait for timeout or signaled alert
    >     sigAlert.wait_for(lock, timeout, []() { return alert || exitThread; });
    >     // mutex is locked again
    >     // check why wait_for() exited
    >     if (exitThread) {
    >       std::cout << "Timer thread exiting...\n";
    >       return;
    >     } else if (alert) {
    >       std::cout << "Timer was interrupted due to alert.\n";
    >       alert = false;
    >     } else {
    >       std::cout << "Timer achieved time-out.\n";
    >     }
    >   }
    > }
    > 
    > int main()
    > {
    >   std::thread threadWait(&timerThread);
    >   // wait a bit
    >   std::cout << "main(): Waiting 300ms...\n";
    >   std::this_thread::sleep_for(300ms);
    >   // sim. interrupt
    >   std::cout << "main(): Sim. interrupt.\n";
    >   { std::lock_guard<std::mutex> lock(mtxAlert);
    >     alert = true;
    >   }
    >   sigAlert.notify_all();
    >   // wait a bit
    >   std::cout << "main(): Waiting 50 ms...\n";
    >   std::this_thread::sleep_for(50ms);
    >   // sim. interrupt
    >   std::cout << "main(): Sim. interrupt.\n";
    >   { std::lock_guard<std::mutex> lock(mtxAlert);
    >     alert = true;
    >   }
    >   sigAlert.notify_all();
    >   // wait a bit
    >   std::cout << "main(): Waiting 50 ms...\n";
    >   std::this_thread::sleep_for(50ms);
    >   // exiting application
    >   exitThread = true;
    >   sigAlert.notify_all();
    >   threadWait.join();
    >   // done
    >   std::cout << "Done.\n";
    > }
    > EOF
    $
    
    

    コンパイルして開始しました:

    $ g++ -std=c++14 -o testCondVar testCondVar.cc
    $ ./testCondVar
    main(): Waiting 300ms...
    Timer achieved time-out.
    Timer achieved time-out.
    main(): Sim. interrupt.
    main(): Waiting 50 ms...
    Timer was interrupted due to alert.
    main(): Sim. interrupt.
    main(): Waiting 50 ms...
    Timer was interrupted due to alert.
    Timer thread exiting...
    Done.
    $
    
    

    注意:

    このサンプルに少なくともC ++ 14が必要な唯一の理由は、std :: chrono_literalsこれにより、たとえば 300ms

    なし std::chrono_literals 、これは次のように書くことができます std::chrono::milliseconds(300) (これは明らかに不便です)。すべてを置き換える std::chrono_literals それぞれ、私はサンプルをコンパイルして実行することができました -std=c++11 同様に。

  • 私はWindows用のスレッドライブラリに精通していません。したがって、代わりに擬似コードを与えることができます。 CとC ++で実装できるはずです。 (以下のコードの構文は明らかに間違っています)

    スリープ用に別のスレッドを作成して実行する

    void * mySleepThread(int x,mutex m)
    {
      sleep(x);
      if(m.isNotDestroyed)
      {
         m.setValue(unlocked);
      }
      return;
    }
    
    

    そして、メインのタイマースレッドは次のようになります。

    void * timer_thread(void*dummy)
    {
      while(1)
      {
        // Check if some callbacks are to be given
        // when all are given, Determine x duration to sleep
    
        create_mutex m1;
        m1.setValue(locked);
        //The Try sleep(x) block
        ExecuteThread(mySleepThread(x,m1));
        //The except block
        while(1)
        {
          if(m1.isNotDestroyed && m1.isLocked && interruptDetected)
            {
              m1.destroy;
              //Execute the interrupt statements here
              break;
            }
           else if(m1.isNotDestroyed && m1.isUnlocked)
           {
             m1.destroy;
             //Execute block of sleep finished without interrupt
             break;
           }
        }
    
        //Do something else block
      }
    }
    
    

あなたの答え