问题
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.
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: It's ok to discard/NOP the interrupts if it occurs when sleep wasn't happening
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)..
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.
回答1:
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:
Missing
#include <mutex>
addedInitialization of
std::atomic<bool> exitThread = false;
changed tostd::atomic<bool> exitThread(false);
I got this when I compiled with
g++
as well as withg++ -std=c++14
. (It seems that-std=c++14
is the default of myg++
.)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 whichg++
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.
回答2:
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
}
}
来源:https://stackoverflow.com/questions/61494611/c-c-how-to-exit-sleep-when-an-interrupt-arrives