用c ++中的信号改变std :: thread的执行流程
我有一个程序启动一个std ::线程执行以下操作:sleep X,执行一个函数,终止。
create std::thread(Xms, &func)
wait Xms
then do func()
end
我想知道是否可以例如发送一个信号给我的std ::线程,以便立即打破睡眠并做func,然后退出。
我是否需要将信号发送到std :: thread :: id才能执行此操作?
我的线程以这种方式启动,并带有一个lambda函数:
template<typename T, typename U>
void execAfter(T func, U params, const int ms)
{
std::thread thread([=](){
std::this_thread::sleep_for(std::chrono::milliseconds(ms));
func(params);
});
thread.detach();
}
如果线程模型不能改变,那么使用std::condition_variable
wait_for
就是要走的路。 在下面的代码片段中,condition_variable的使用被包装到一个必须在线程中共享对象的类中。
#include <iostream>
#include <atomic>
#include <condition_variable>
#include <thread>
#include <chrono>
class BlockCondition
{
private:
mutable std::mutex m;
std::atomic<bool> done;
mutable std::condition_variable cv;
public:
BlockCondition()
:
m(),
done(false),
cv()
{
}
void wait_for(int duration_ms)
{
std::unique_lock<std::mutex> l(m);
int ms_waited(0);
while ( !done.load() && ms_waited < duration_ms )
{
auto t_0(std::chrono::high_resolution_clock::now());
cv.wait_for(l, std::chrono::milliseconds(duration_ms - ms_waited));
auto t_1(std::chrono::high_resolution_clock::now());
ms_waited += std::chrono::duration_cast<std::chrono::milliseconds>(t_1 - t_0).count();
}
}
void release()
{
std::lock_guard<std::mutex> l(m);
done.store(true);
cv.notify_one();
}
};
void delayed_func(BlockCondition* block)
{
block->wait_for(1000);
std::cout << "Hello actual workn";
}
void abortSleepyFunction(BlockCondition* block)
{
block->release();
}
void test_aborted()
{
BlockCondition b();
std::thread delayed_thread(delayed_func, &b);
abortSleepyFunction(&b);
delayed_thread.join();
}
void test_unaborted()
{
BlockCondition b();
std::thread delayed_thread(delayed_func, &b);
delayed_thread.join();
}
int main()
{
test_aborted();
test_unaborted();
}
请注意,可能会有虚假唤醒提前中止等待呼叫。 为了说明这一点,我们计算实际等待的毫秒数,并继续等待,直到完成标志设置。
正如评论中指出的那样,这并不是解决问题的最明智的方法。 由于实施适当的中断机制非常复杂,而且极易出错,因此建议采取以下解决方法:
而不是整个超时睡觉,只需循环一个固定的小尺寸(例如10毫秒)的睡眠,直到所需的持续时间已过。 在每次睡眠之后,您检查原子标志是否请求中断。 这是一个肮脏的解决方案,但却是最快的解决方案。
或者,为每个线程提供一个condition_variable
然后wait
它,而不是执行this_thread::sleep
。 通知条件变量以指示中断请求。 您可能仍然需要一个额外的标志来防止虚假唤醒,所以您不会意外返回太早。
好吧,为了解决这个问题,我发现了一个新的实现,它的灵感来自于你的所有答案,所以非常感谢。
首先我要在主游戏项目中做一个BombHandler物品。 它将有一个包含所有炸弹项目的属性。
这个BombHandler将是一个单身人士,包含一个将在一个线程中执行的timerLoop()函数(这种方式我只使用一个线程为xxx炸弹,方式更有效)
timerLoop()将休眠(50),然后通过整个std :: list元素并调用Bomb :: incrTimer(),他们将无限期地增加其内部_timer属性10ms,并检查必须爆炸的炸弹。
例如,当它们达到2000ms时,BombHandler.explode()将被调用,爆炸炸弹并将其删除。
如果另一个炸弹在范围内,Bomb :: touchByFire()将被调用,并且将炸弹的内部属性_timer设置为TIME_TO_EXPLODE(1950ms)。
然后由BombHandler :: explode()在50ms后爆炸。
这不是一个好的解决方案吗?
再次感谢您的回答! 希望这可以帮助。
链接地址: http://www.djcxy.com/p/5203.html上一篇: Change std::thread execution flow with signals in c++
下一篇: Replacing std::async with own version but where should std::promise live?