用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?