多个std::线程和主程序执行出现问题

Trouble with multiple std::threads and main program execution

本文关键字:执行 问题 std 线程 多个 主程序      更新时间:2023-10-16

我几天来一直在努力想出一种机制来启动一些定时器,而不让它为主程序的执行计时。.join().detach()wait_until()等的组合

我有一个std::thread的矢量,我想:

  • 执行第一个位置
  • 等它结束
  • 执行下一个位置
  • 等它结束

与此同时,我的应用程序的其余部分正在运行,用户点击东西,等等。我想到的一切似乎都是:

  • 在计时器运行时阻止主程序运行

  • 从主线程分离,但计时器同时运行,就像我希望的那样,在上一个线程完成后运行

我甚至发布了:C++11 std::threads并等待线程完成,但似乎都没有我能理解的解决方案。

我应该使用std::launch::async吗?

编辑:我不知道为什么这对我来说如此难以理解。我的意思是,电子游戏总是这样。以《小塔》为例。你在地板上备货,从你开始备货到物品备货,每一项操作都会延迟,并触发HUD弹出,显示"地板现在备货了"。与此同时,整个游戏一直在运行,让你做其他事情。我一定很笨,因为我搞不清楚。

这段代码将在单独的线程中执行空任务的std::vector

typedef std::vector<std::function< void() >> task_list;
typedef std::chrono::high_resolution_clock::duration timing;
typedef std::vector< timing > timing_result;
timing_result do_tasks( task_list list ) {
  timing_result retval;
  for (auto&& task: list) {
    std::chrono::high_resolution_clock::time_point start = std::chrono::high_resolution_clock::now();
    task();
    std::chrono::high_resolution_clock::time_point end = std::chrono::high_resolution_clock::now();
    retval.push_back( end-start );
  }
  return retval;
}
std::future<timing_result> execute_tasks_in_order_elsewhere( task_list list ) {
  return std::async( std::launch::async, do_tasks, std::move(list) );
}

这应该在主线程之外串行运行每个任务,并返回包含计时结果的std::future

如果你想把计时结果分成小块(即在它们都准备好之前),你就必须做更多的工作。我会从std::packaged_task开始,返回一个std::vector<std::future< timing >>,然后从那里开始。

上面的代码是未经测试/未编译的,但不应该有任何根本的缺陷。

您会注意到,上面没有使用std::threadstd::thread是一个低级别的工具,您应该在它之上构建工具,而不是应该直接使用的工具(它非常脆弱,因为在销毁之前需要joined或detached等)。

虽然std::async没有什么可写的,但它非常适合快速而肮脏的多线程,在这种情况下,您希望执行串行任务并在"其他地方"执行。通过std::future缺乏像样的信令使其不太通用(这也是您可能想要围绕std::thread编写更高级别抽象的原因)。

这里有一个将运行一系列任务,其间的延迟最小:

#include <chrono>
#include <iostream>
#include <vector>
#include <functional>
#include <thread>
#include <future>
typedef std::chrono::high_resolution_clock::duration duration;
typedef std::chrono::high_resolution_clock::time_point time_point;
typedef std::vector<std::pair<duration, std::function< void() >>> delayed_task_list;
void do_delayed_tasks( delayed_task_list list ) {
  time_point start = std::chrono::high_resolution_clock::now();
  time_point last = start;
  for (auto&& task: list) {
    time_point next = last + task.first;
    duration wait_for = next - std::chrono::high_resolution_clock::now();
    std::this_thread::sleep_for( wait_for );
    task.second();
    last = next;
  }
}
std::future<void> execute_delayed_tasks_in_order_elsewhere( delayed_task_list list ) {
  return std::async( std::launch::async, do_delayed_tasks, std::move(list) );
}
int main() {
  delayed_task_list meh;
  meh.emplace_back( duration(), []{ std::cout << "hello worldn"; } );
  std::future<void> f = execute_delayed_tasks_in_order_elsewhere( meh );
  f.wait(); // wait for the task list to complete: you can instead store the `future`
}

这应该使助手CCD_ 17线程睡眠(至少与运行每个任务之前使用的持续时间一样长)。正如所写的那样,执行每项任务所花费的时间不计入延迟,因此,如果任务花费的时间比延迟时间长,则最终任务运行时几乎没有延迟。如果你愿意的话,改变它应该很容易。

您的麻烦是可以理解的,因为您需要的是一个事件循环,而C++还没有标准的定时器来阻止事件循环。您需要使用其他框架(如Qt、Boost.Asio(?)或不可移植的API(select()等)来编写事件循环。