我有一个程序启动一个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();
}
请注意,可能是虚假的唤醒,会过早地中止wait调用。为了说明这一点,我们计算实际等待的毫秒数,并继续等待,直到设置完成标志。
正如在评论中指出的那样,这并不是解决问题的最明智的方法。由于实现适当的中断机制非常复杂,而且非常容易出错,因此这里有一些解决方法的建议:
不要在整个超时时间内休眠,而是简单地循环一个固定的小长度的休眠(例如10毫秒),直到所需的持续时间过去。每次睡眠后,检查原子标志是否请求中断。这是一个肮脏的解决方案,但却是最快的。
或者,为每个线程提供condition_variable
并对其执行wait
而不是执行this_thread::sleep
。通知条件变量以指示中断请求。您可能仍然需要一个额外的标志来防止虚假的唤醒,这样您就不会意外地过早返回。
好的,为了弄清楚这个问题,我发现了一个新的实现,它受到了你们所有答案的启发,所以非常感谢。
首先我要在主游戏道具中添加一个BombHandler道具。它将有一个包含所有Bomb项的属性。
这个BombHandler将是一个单例,包含一个timerLoop()函数,它将在一个线程中执行(这样我只使用一个线程来处理xxx个炸弹,更有效)
timerLoop()将ussleep(50),然后遍历整个std::list元素并调用Bomb::incrTimer(),后者将其内部_timer属性无限地增加10ms,并检查必须爆炸的炸弹。
例如,当它们达到2000ms时,bombhandler . explosion()将被调用,引爆炸弹并删除它。
如果另一个炸弹在范围内,炸弹::touchByFire()将被调用,并设置炸弹的内部属性,_timer,为time_to_explosion (1950ms)。
那么它将在50ms后被BombHandler:: explosion()引爆。
这不是一个很好的解决方案吗?
再次感谢你的回答!希望这能帮到你。