简体   繁体   English

从usleep唤醒std :: thread

[英]Wake up a std::thread from usleep

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. 我绝对不是线程专家,所以如果可能的话,不要假设任何东西。

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) 标准库为timed_mutex提供了一个名为try_lock_for ,该try_lock_for将尝试锁定互斥锁一段时间,然后继续执行(并返回失败指示)

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. 它还可以通过包含waitUntil函数来等待,直到一个时间序列对应timed_mutex的其他定时等待函数try_lock_until但我会将其作为练习留给感兴趣的人,因为它似乎是一个简单的修改。


#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 Coliru上的示例和使用

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. 一种可能的解决方法是使用condition_variable::sleep_for以及mutex和布尔条件。

#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: 或者,您可以使用Boost.Thread库来实现中断点概念:

#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();

}

"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. 不,根据c ++标准机制,没有办法这样做。

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: 除了usleep()之外,还有一个不推荐使用的POSIX函数:

Issue 6 问题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. 应用IEEE Std 1003.1-2001 / Cor 2-2004,项目XSH / TC2 / D6 / 144,将描述从“过程'信号掩码”更新为“线程的信号掩码”,并添加一个usleep()函数需要的语句不可重入。

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 . 即使从std::thread声明,任何其他sleep()函数也是如此。

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. 正如其他答案或注释中所提到的,您需要使用时间同步机制,如std::timed_mutex或来自线程函数的std::condition_variable

One possible approach:(There are many ways to accomplish..also its not good idea to use sleep in your thread) 一种可能的方法:(有很多方法可以实现......在你的线程中使用sleep也不是一个好主意)

///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();
}

只需使用信号量,调用sem_timedwait而不是usleep ,并在调用join之前调用sem_post

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);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM