C++ 从usleep唤醒一个std::线程
考虑以下示例:C++ 从usleep唤醒一个std::线程,c++,multithreading,C++,Multithreading,考虑以下示例: #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 s
#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();
}
#包括
#包括
#包括
#包括
#包括
虚无困倦{
usleep(1.0E15);
}
int main(){
标准:线程休眠线程(休眠);
//不知怎么把它唤醒。。。?
sleepy_thread.join();
}
这里我们有一条永远沉睡的线。我想加入它,而不必永远等待它从美国睡眠计划中自发醒来。有没有办法从外人的“嘿,伙计,醒醒!”中分辨出来,这样我就可以在合理的时间内加入它
我绝对不是线程方面的专家,所以如果可能的话,不要假设任何事情。一种可能的方法:(有很多方法可以实现……而且在线程中使用睡眠也不是一个好主意)
只需使用一个信号量,调用而不是
usleep
,在调用join
之前先调用睡眠一小段时间,然后查看变量是否已更改
#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);
}
#包括
#包括
#包括
std::原子共享dvar(1);
虚无困倦
{
while(sharedVar.load())
{
美国LEEP(500);
}
}
int main()
{
标准:线程休眠线程(休眠);
//醒醒
sharedVar.store(0);
}
“有没有办法从外人那里分辨出来”嘿,伙计,醒醒!“,以便我能在合理的时间内加入它?”
不,没有根据C++标准机制来做的。
好吧,为了唤醒你的线程,你需要一个机制,让其他线程控制它。此外,还有一个不推荐使用的POSIX函数:
第6期
更新说明以避免在应用要求中使用术语“必须”
此功能已标记为过时。
IEEE Std 1003.1-2001/Cor 2-2004第XSH/TC2/D6/144项适用,将描述从“进程的信号掩码”更新为“线程的信号掩码”,并添加了一条声明,即usleep()
函数不需要重入
您无法控制另一个线程,它将调用该函数。对于任何其他
sleep()
函数,即使从中声明,也是如此
如其他答案或评论中所述,您需要使用线程函数中的可计时同步机制,如a或a。否,不可能使用标准库中的线程 一种可能的解决方法是为使用
condition\u变量::sleep\u以及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();
}
#包括
#包括
#包括
std::mutex mymutex;
std::条件变量mycond;
布尔标志=假;
虚无困倦{
std::唯一锁(mymutex);
我的命令。等待(锁定),
标准时间:秒(1000),
[](){返回标志;});
}
int main()
{
标准:线程休眠线程(休眠);
{
std::lock_guard lock(mymutex);
flag=true;
我的命令通知你一个();
}
sleepy_thread.join();
}
或者,您可以使用实现中断点概念的库:
#包括
虚无困倦
{
//此线程::sleep是一个中断点。
boost::this_线程::sleep_for(boost::chrono::seconds(1000));
}
int main()
{
boost::线程t(sleepy);
t、 中断();
t、 join();
}
其他答案是,您可以使用定时静音来完成此任务。我创建了一个使用定时互斥锁的小类来阻止“睡眠”线程,如果您想尽早“唤醒”线程,请释放互斥锁。标准库为timed_mutex
提供了一个名为try_lock_for
的函数,该函数将尝试锁定一段时间的互斥锁,然后继续执行(并返回故障指示)
这可以封装在一个类中,如下面的实现,它只允许单个调用唤醒等待的线程。它还可以通过包含一个用于等待时间序列的waitUntil
函数来改进,该函数对应于timed_mutex
的另一个定时等待函数try_lock_until
,但我将把它作为一个练习留给感兴趣的人,因为这似乎是一个简单的修改
IIRCusleep(1.0E15)上的示例和使用
不接受浮点值
或双精度
值???@πάνταῥεῖ: 那又怎样1e15
可隐式转换为int
。虽然这是一个相当多的int
@LightnessRacesinOrbit“虽然这是一个相当多的int
”是我的观点。总之,这是一个很大的值。@OP您还应该注意,usleep()
是。发送一个信号怎么样?“在线程中使用睡眠不是一个好主意”为什么呢?您应该充实答案的std::mutex
部分。这个代码是非法的,因为对sharedVar
的两个访问冲突,根据C++标准,不可能是非法的。你是说没有定义的行为吗?如果sleepy在一个循环中读取sharedVar的旧版本,它将在一个循环后读取较新的值。问题不是sleepy可能读取旧版本。问题是任何事情都可能发生。至少std::atomic sharedVar=1代码>请@πάνταῥεῖ: 最好不要这样做,因为它无法编译。我使用pthread的答案被否决了。这也使用了一个pHooLoad库。旗语实际上是C++标准吗?我能想到的最好的代理是。我实际上非常喜欢这个主意。。。!为什么会被否决?这个例子使用Linux特定的usleep
,为什么我们不能在这里使用Linux特定的信号量?
#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();
}
#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();
}
#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();
}
}
};
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);
}
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