C/C++: How to exit sleep() when an interrupt arrives?

前端 未结 2 1348
逝去的感伤
逝去的感伤 2020-12-21 12:02

I\'m looking for a way to exit sleep when an user interrupt arrives - its important to exit sleep rather than do this: interrupt sleep , do ISR processing,

相关标签:
2条回答
  • 2020-12-21 12:24

    I'm not familiar with thread libraries for windows. So I can give a pseudo-code instead. You should be able to implement it in C as well as C++. (The syntax of code below is obviously wrong)

    Create a separate thread for sleep to execute

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

    And your main timer thread would look something like:

    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
    
      }
    }
    
    0 讨论(0)
  • 2020-12-21 12:35

    To wait for a certain time or on a certain event, I would use a combination of std::mutex and std::condition_variable and specifically std::condition_variable::wait_for() to await either time-out or a signaled change of something.

    A minimal sample program for demonstration:

    #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";
    }
    

    Output:

    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.
    

    Live Demo on coliru


    OP claimed per comment that this sample didn't compile properly on cygwin. I tried on my side and can confirm some minor issues which I fixed:

    1. Missing #include <mutex> added

    2. Initialization of std::atomic<bool> exitThread = false; changed to

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

      I got this when I compiled with g++ as well as with g++ -std=c++14. (It seems that -std=c++14 is the default of my g++.)

      When I use g++ -std=c++17 instead I don't get any complaint. I strongly believe that has something to do with copy-elision which g++ applies with -std=c++17 but not prior.

    However, this is my sample session with the slightly reviewed code on my Windows 10 laptop in 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
    
    $
    

    Compiled and started:

    $ 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.
    
    $
    

    Note:

    The only reason that at minimum C++14 is required for this sample is the usage of the std::chrono_literals which enables the usage of e.g. 300ms.

    Without std::chrono_literals, this could be written as std::chrono::milliseconds(300) (which is admittedly less convenient). Replacing all std::chrono_literals respectively, I was able to compile and run the sample with -std=c++11 as well.

    0 讨论(0)
提交回复
热议问题