2

我有一个程序启动一个 std::thread 执行以下操作:睡眠 X,执行一个函数,终止。

create std::thread(Xms, &func)
  wait Xms
  then do func()
  end

我想知道我是否可以例如向我的 std::thread 发送一个信号,以便立即打破睡眠并执行 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();
}
4

3 回答 3

2

正如评论中指出的那样,这首先不是解决问题的最聪明的方法。由于实施适当的中断机制非常复杂且极易出错,因此以下是解决方法的建议:

与其在整个超时时间内休眠,不如简单地循环一个固定的小尺寸(例如 10 毫秒)的休眠,直到经过所需的持续时间。每次睡眠后,您检查一个原子标志是否请求中断。这是一个肮脏的解决方案,但却是最快的。

或者,为每个线程提供 acondition_variable并对其执行 await而不是执行this_thread::sleep. 通知条件变量指示中断请求。你可能仍然需要一个额外的标志来防止虚假唤醒,这样你就不会意外地过早返回。

于 2013-06-03T14:34:42.870 回答
2

如果无法更改线程模型,则使用wait_forof将是可行的方法。std::condition_variable在下面的代码片段中,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 work\n";
}

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();
}

请注意,可能存在过早中止等待调用的虚假唤醒。考虑到这一点,我们计算实际等待的毫秒数并继续等待,直到设置完成标志。

于 2013-06-03T15:09:03.970 回答
0

好的,为了弄清楚这一点,我找到了一个新的实现,它受到您所有答案的启发,非常感谢。

首先我要做一个 BombHandler 项目,在主游戏项目中。它将有一个包含所有 Bomb 项目的属性。

这个 BombHandler 将是一个单例,包含一个将在线程中执行的 timerLoop() 函数(这样我只使用一个线程来处理 xxx 炸弹,这样更有效)

timerLoop() 将 usleep(50) 然后通过整个 std::list 元素并调用 Bomb::incrTimer() 将其内部 _timer 属性无限增加 10 毫秒,并检查必须爆炸的炸弹。

例如,当它们达到 2000 毫秒时,将调用 BombHandler.explode(),引爆炸弹并将其删除。

如果另一个炸弹在范围内,Bomb::touchByFire() 将被调用,并将 Bomb 的内部属性 _timer 设置为 TIME_TO_EXPLODE (1950ms)。

然后它会在 50ms 后被 BombHandler::explode() 爆炸。

这不是一个很好的解决方案吗?

再次感谢您的回答!希望这能有所帮助。

于 2013-06-04T11:30:37.660 回答