C/C ++:中断到达时如何退出sleep()? [英] C/C++: How to exit sleep() when an interrupt arrives?

查看:529
本文介绍了C/C ++:中断到达时如何退出sleep()?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在寻找一种方法,可在用户中断到达时退出睡眠状态-重要的是退出睡眠,而不是这样做:中断睡眠,进行ISR处理并返回睡眠状态-是我正在寻找解决方案的地方.

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, and go back to sleep - which is what I'm finding solutions for.

我正在C ++中寻找类似的东西-C中的等效项甚至更好:

I'm looking for something like this in C++ - an equivalent in C is even better:

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
  }
}

到达的中断通常会告诉您应该减少睡眠,以使计时器线程更早地进行回调.但是不管用例如何,我只需要在中断到达时以某种方式退出睡眠状态.我只是找不到有关如何执行此操作的信息.

The arriving interrupt will mostly tell that the sleep should be reduced for the timer thread to give callbacks earlier. But irrespective of the usecase, I just need the sleep to be exited in some way when interrupt arrives. I just couldn't find info on how to do this.

PS:如果在没有睡眠的情况下发生中断,则可以放弃/取消中断

PS: It's ok to discard/NOP the interrupts if it occurs when sleep wasn't happening

这是在Windows 10(C/C ++)上的Cygwin gcc v9.3.0上-不需要代码可移植,因此任何特定于平台的解决方案也可以.使用Eclipse进行处理(最新日期为2020年4月).

This is on Cygwin gcc v9.3.0 on Windows 10 (C/C++) - Don't need the code to be portable, so any platform specific solution is ok as well. Working on this using Eclipse (latest - dated 04/2020)..

如果还有其他类似的解决方案(不使用sleep()和中断),欢迎您听听.我只是在寻找一种不涉及轮询的方法.

If there's some other solution which is similar to this working (which doesn't use sleep() and interrupts), would be welcome to hear it. I'm just looking for a way which doesn't involve polling.

推荐答案

要在特定事件上等待特定时间,我会使用

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

输出:

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.

在大肠杆菌上进行实时演示

OP根据评论声称此示例无法在 cygwin 上正确编译. .我已经站在一边,可以确认一些我已解决的小问题:

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. 添加了#include <mutex>缺少

std::atomic<bool> exitThread = false;的初始化已更改为

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

当我用g++以及g++ -std=c++14进行编译时,我得到了这个. (看来-std=c++14是我的g++的默认设置.)

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++.)

当我使用g++ -std=c++17时,我没有任何抱怨.我坚信这与 copy-elision ,其中g++适用于-std=c++17,但不适用于先前版本.

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.

但是,这是我的示例会话,其中在Windows 10便携式计算机上的 cygwin64 > :

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

$

已编译并启动:

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

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.

如果没有std::chrono_literals,可以将其写为std::chrono::milliseconds(300)(这显然不太方便).分别替换所有std::chrono_literals,我也可以使用-std=c++11编译并运行示例.

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.

这篇关于C/C ++:中断到达时如何退出sleep()?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆