Consider the following example:
#include
#include
#include
#include
#include
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
#include
#include
#include
#include
// 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& 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(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