Wake up a std::thread from usleep

后端 未结 6 2397
借酒劲吻你
借酒劲吻你 2021-02-14 05:28

Consider the following example:

#include 
#include 
#include 

#include 
#include 

         


        
6条回答
  •  忘了有多久
    2021-02-14 06:24

    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

提交回复
热议问题