C / C ++: Как выйти из sleep (), когда приходит прерывание? - PullRequest
1 голос
/ 29 апреля 2020

Я ищу способ выхода из режима сна, когда приходит пользовательское прерывание - важно выйти из режима сна, а не делать это: прерывать режим сна, выполнять обработку ISR и go возвращать в режим сна - Вот для чего я нахожу решения.

Я ищу что-то подобное в 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: Это нормально, чтобы сбрасывать / прерывать прерывания, если это происходит, когда сон не происходит

Это на Cygwin g cc v9.3.0 на Windows 10 (C / C ++) - код не нужен для переносимости, поэтому любое решение для платформы c также подойдет. Работая над этим с использованием Eclipse (последняя версия от 04/2020) ..

Если есть какое-то другое решение, похожее на это (которое не использует sleep () и interruppts), приветствую вас услышать Это. Я просто ищу способ, который не включает опрос.

Ответы [ 2 ]

2 голосов
/ 29 апреля 2020

Чтобы подождать определенное время или для определенного события, я бы использовал комбинацию 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 . Я попытался на своей стороне и могу подтвердить некоторые незначительные проблемы, которые я исправил:

  1. Отсутствует #include <mutex> добавлено

  2. Инициализация std::atomic<bool> exitThread = false; изменена на

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

    Я получил это, когда скомпилировал с g++, а также с g++ -std=c++14. (Кажется, что -std=c++14 является значением по умолчанию для моего g++.)

    Когда я использую g++ -std=c++17, я не получаю никаких жалоб. Я твердо верю, что это как-то связано с copy-elision , которое g++ применимо к -std=c++17, но не ранее.

Однако Это мой пример сеанса со слегка рассмотренным кодом на моем Windows 10 ноутбуке в 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.

0 голосов
/ 29 апреля 2020

Я не знаком с библиотеками потоков для 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

  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...