Consider the following example:
#include <iostream>
#include <fstream>
#include <unistd.h>
#include <signal.h>
#include <thread>
void sleepy() {
usleep(1.0E15);
}
int main() {
std :: thread sleepy_thread(sleepy);
// Wake it up somehow...?
sleepy_thread.join();
}
Here we have a thread that just sleeps forever. I want to join it, without having to wait forever for it to spontaneously wake from usleep. Is there a way to tell it from the extern "hey man, wake up!", so that I can join it in a reasonable amount of time?
I am definitely not an expert on threads, so if possible don't assume anything.
You can use std::promise/std::future as a simpler alternative to a bool / condition_variable / mutex in this case. A future is not susceptible to spurious wakes and doesn't require a mutex for synchronisation. Save this answer.
If the threads are sleeping with Thread. sleep(...) , you can wake them up with Thread. interrupt() . Make sure you're handling the InterruptedException and testing Thread.
The sleep () function causes the program or the process in which it is called, to suspend its execution temporarily for a period of time in seconds specified by the function parameter. Execution is suspended until the requested time is elapsed or a signal or an interrupt is delivered to the function.
No, it is not possible using the threads from the standard library.
One possible workaround is to use condition_variable::sleep_for
along with a mutex
and a boolean condition.
#include <mutex>
#include <thread>
#include <condition_variable>
std::mutex mymutex;
std::condition_variable mycond;
bool flag = false;
void sleepy() {
std::unique_lock<std::mutex> lock(mymutex);
mycond.wait_for( lock,
std::chrono::seconds(1000),
[]() { return flag; } );
}
int main()
{
std :: thread sleepy_thread(sleepy);
{
std::lock_guard<std::mutex> lock(mymutex);
flag = true;
mycond.notify_one();
}
sleepy_thread.join();
}
Alternatively, you can use the Boost.Thread library, which implements the interruption-point concept:
#include <boost/thread/thread.hpp>
void sleepy()
{
// this_thread::sleep_for is an interruption point.
boost::this_thread::sleep_for( boost::chrono::seconds(1000) );
}
int main()
{
boost::thread t( sleepy );
t.interrupt();
t.join();
}
Other answers are saying you can use a timed muted to accomplish this. I've put together a small class using a timed mutex to block the 'sleeping' threads, and release the mutex if you want to 'wake' them early. The standard library provides a function for timed_mutex
called try_lock_for
which will try to lock a mutex for a period of time, before continuing on anyway (and returning an indication of failure)
This can be encapsulated in a class, like the following implementation, which only allows a single call to wake waiting threads. It could also be improved by including a waitUntil
function for waiting until a time series to correspond to the timed_mutex
's other timed waiting function, try_lock_until
but I will leave that as an exercise to the interested, since it seems a simple modification.
#include <iostream>
#include <mutex>
#include <thread>
#include <chrono>
#include <atomic>
// one use wakable sleeping class
class InterruptableSleeper{
std::timed_mutex
mut_;
std::atomic_bool
locked_; // track whether the mutex is locked
void lock(){ // lock mutex
mut_.lock();
locked_ = true;
}
void unlock(){ // unlock mutex
locked_ = false;
mut_.unlock();
}
public:
// lock on creation
InterruptableSleeper() {
lock();
}
// unlock on destruction, if wake was never called
~InterruptableSleeper(){
if(locked_){
unlock();
}
}
// called by any thread except the creator
// waits until wake is called or the specified time passes
template< class Rep, class Period >
void sleepFor(const std::chrono::duration<Rep,Period>& timeout_duration){
if(mut_.try_lock_for(timeout_duration)){
// if successfully locked,
// remove the lock
mut_.unlock();
}
}
// unblock any waiting threads, handling a situation
// where wake has already been called.
// should only be called by the creating thread
void wake(){
if(locked_){
unlock();
}
}
};
The following code:
void printTimeWaited(
InterruptableSleeper& sleeper,
const std::chrono::milliseconds& duration){
auto start = std::chrono::steady_clock::now();
std::cout << "Started sleep...";
sleeper.sleepFor(duration);
auto end = std::chrono::steady_clock::now();
std::cout
<< "Ended sleep after "
<< std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count()
<< "ms.\n";
}
void compareTimes(unsigned int sleep, unsigned int waker){
std::cout << "Begin test: sleep for " << sleep << "ms, wakeup at " << waker << "ms\n";
InterruptableSleeper
sleeper;
std::thread
sleepy(&printTimeWaited, std::ref(sleeper), std::chrono::milliseconds{sleep});
std::this_thread::sleep_for(std::chrono::milliseconds{waker});
sleeper.wake();
sleepy.join();
std::cout << "End test\n";
}
int main(){
compareTimes(1000, 50);
compareTimes(50, 1000);
}
prints
Begin test: sleep for 1000ms, wakeup at 50ms
Started sleep...Ended sleep after 50ms.
End test
Begin test: sleep for 50ms, wakeup at 1000ms
Started sleep...Ended sleep after 50ms.
End test
Example & Use on Coliru
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With