Wake up a std::thread from usleep

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

Consider the following example:

#include 
#include 
#include 

#include 
#include 

         


        
相关标签:
6条回答
  • 2021-02-14 06:07

    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();
    
    }
    
    0 讨论(0)
  • 2021-02-14 06:12

    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();
    }
    
    0 讨论(0)
  • 2021-02-14 06:14

    "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.

    0 讨论(0)
  • 2021-02-14 06:19

    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);
    }
    
    0 讨论(0)
  • 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 <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
    0 讨论(0)
  • 2021-02-14 06:30

    Just use a semaphore, call sem_timedwait instead of usleep, and call sem_post before calling join

    0 讨论(0)
提交回复
热议问题