Consider the following example:
#include
#include
#include
#include
#include
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();
}
One possible approach:(There are many ways to accomplish..also its not good idea to use sleep in your thread)
///Define a mutex
void sleepy()
{
//try to take mutex lock which this thread will get if main thread leaves that
//usleep(1.0E15);
}
int main()
{
//Init the Mutex
//take mutex lock
std :: thread sleepy_thread(sleepy);
//Do your work
//unlock the mutex...This will enable the sleepy thread to run
sleepy_thread.join();
}
"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?"
No, there's no way to do so according c++ standard mechanisms.
Well, to get your thread being woken, you'll need a mechanism that leaves other threads in control of it. Besides usleep() is a deprecated POSIX function:
Issue 6
The DESCRIPTION is updated to avoid use of the term "must" for application requirements.
This function is marked obsolescent.
IEEE Std 1003.1-2001/Cor 2-2004, item XSH/TC2/D6/144 is applied, updating the DESCRIPTION from "process' signal mask" to "thread's signal mask", and adding a statement that the
usleep()
function need not be reentrant.
there's no way you could get control of another thread, that's going to call that function.
Same thing for any other sleep()
functions even if declared from std::thread.
As mentioned in other answers or comments, you'll need to use a timeable synchronization mechanism like a std::timed_mutex or a std::condition_variable from your thread function.
Sleep for a short amount of time and look to see if a variable has changed.
#include <atomic>
#include <unistd.h>
#include <thread>
std::atomic<int> sharedVar(1);
void sleepy()
{
while (sharedVar.load())
{
usleep(500);
}
}
int main()
{
std :: thread sleepy_thread(sleepy);
// wake up
sharedVar.store(0);
}
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
Just use a semaphore, call sem_timedwait instead of usleep
, and call sem_post before calling join