C++ 中的多线程 - 显示动画直到另一个线程完成

Multithreading in C++ - Display animation until another thread has completed

前言:这是我第一次尝试用任何语言编写多线程程序。我之前没有使用 std::thread 的经验,也没有描述多线程程序的经验。如果您需要更多信息来回答这个问题,或者我是否可以改写任何内容以使我的问题更清楚,请告诉我。

假设我有一个简单的动画函数 animate,它(现在)无限期地运行;和另一个函数 task,它表示要执行的任意代码。

#include <string>

// a simple rotating stick animation: | -> / -> - -> \

void animate()
{
  std::string syms = "|/-\";
  while (true)
  {
    for (unsigned int ii = 0; ii < syms.length(); ++ii)
    {
      std::cout << syms[ii];
      std::cout << std::string(1, '\b');
    }
  }
}

// arbitrary function

void task()
{
  // code to do something else goes here
}

int main (int argc, char* argv[])
{
  // execute task and animate at the same time;
  // return from animate once task has completed
  return 0;
}

如何使用 std::thread(或其他 header/library)让 taskanimate 相互通信,这样 task在“后台”运行并且 animate 一直运行到 task 完成?

我已经使用了您的示例代码并尝试用 std::thread 填补您的意图中的空白。我添加了一些内联评论来解释发生了什么。如果有什么不清楚的地方,或者我理解错了,欢迎在评论中提问。

我想强调的是,这个示例 使用 std::thread 在玩具示例中创建和加入一个单独的线程。 它不会以正确的方式在线程之间同步共享数据。 MT 环境中的共享数据是事情变得棘手的地方,最糟糕的是它可能会产生一些最难调试的错误。这就是为什么书籍和工作示例对于任何实质性多线程程序都很重要的原因。

#include <string>
#include <thread>
#include <chrono>
#include <iostream>

// a simple rotating stick animation: | -> / -> - -> \

//
void animate(bool * should_animate)
{
  // Using this namespace lets us use the "100ms" time literal in the sleep_for() function argument.
  using namespace std::chrono_literals;

  std::string syms = "|/-\";
  while (*should_animate)
  {
    for (unsigned int ii = 0; ii < syms.length(); ++ii)
    {
      std::cout << syms[ii];
      std::cout << std::string(1, '\b');

      // I had to flush cout so that the animation would show up
      std::cout.flush();
      // I added some delay here so that the animation is more visible
      std::this_thread::sleep_for(100ms);
    }
  }
}

// arbitrary function

void task()
{
  using namespace std::chrono_literals;
  // I have this thread waiting for 2 seconds to simulate a lot of work being done
  std::this_thread::sleep_for(2s);
}

int main (int argc, char* argv[])
{

  // This line creates a thread from the animate() function
  // The std::thread constructor is flexible, in that it can take a function with any number and type of arguments and
  // make a thread out of it
  // Once the thread is created, it gets sent to the operating system for scheduling right away in a separate thread
  // I'm passing in a pointer to `should_animate` to use that value as a basic way to communicate to the animate thread to signal when it should stop running.
  // I'm doing this to keep the example simple, but I stress that this isn't a good idea for larger scale programs
  // Better to use propper signals or event queues
  bool should_animate = true;
  std::thread thread_animate(animate, &should_animate);

  // This line creates a thread for the worker task
  // That separate thread can be referenced by tis std::thread object
  // Once the functions finish running, the thread associated with it is "joined"
  std::thread thread_task(task);

  // 'join' pauses the main thread to wait for the associated thread to finish running in the background.
  thread_task.join();

  // By this point in the program, the `task()` function has finished running, so we can flag
  // the animate task to finish running so its thread can be joined
  should_animate = false;
  // Wait for the animate thread to get the message and finish
  thread_animate.join();


  std::cout << "Done!" << std::endl;
  return 0;
}

如果您想进一步了解,这里有一些我推荐的链接。

  • 这是我能在 google 的第一页找到的最好的教程(大多数结果似乎都很糟糕)。似乎是一个很好的起点 https://solarianprogrammer.com/2011/12/16/cpp-11-thread-tutorial/
  • cppreference 是我所知道的最好的 C++ 参考站点,我通常每天至少有一个选项卡在上面。因为它是参考,所以很难直接深入研究它。此页面的每个部分 header 涵盖一个多线程主题。 “线程”和“互斥”是机器翻译中最常用的东西。 https://en.cppreference.com/w/cpp/thread