[英]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.