【问题标题】:How do I make threads run sequentially instead of concurrently?如何使线程按顺序运行而不是同时运行?
【发布时间】:2013-08-13 19:03:17
【问题描述】:

例如,我希望每个线程在前一个线程完成之前不开始运行,是否有一个标志,例如thread.isRunning()

#include <iostream>
#include <vector>
#include <thread>
using namespace std;

void hello() {
    cout << "thread id: " << this_thread::get_id() << endl;
}

int main() {

    vector<thread> threads;

    for (int i = 0; i < 5; ++i)
        threads.push_back(thread(hello));


    for (thread& thr : threads)
        thr.join();

    cin.get();
    return 0;
}

我知道线程是要同时运行的,但是如果我想控制顺序怎么办?

【问题讨论】:

  • 听起来像是 XY 问题。为什么要控制订单?你的用例是什么?
  • 如果您不希望一个线程在另一个线程完成之前运行,那么您可能不需要线程。只需编写两个函数调用,一个接一个。
  • 这个问题,“我怎样才能使从一开始就为并发操作而设计的东西按顺序运行”这个问题经常出现。

标签: c++ multithreading c++11


【解决方案1】:

没有thread.isRunning()。你需要一些同步原语来做到这一点。 以std::condition_variable 为例。

【讨论】:

    【解决方案2】:

    一种可行的方法是使用std::async。根据std::async 的当前定义,std::async 启动的操作的关联状态会导致返回的std::future 的析构函数阻塞,直到操作完成。这可能会限制可组合性并导致代码看似并行运行,但实际上是按顺序运行。

    {
        std::async(std::launch::async, []{ hello(); });
        std::async(std::launch::async, []{ hello(); });  // does not run until hello() completes
    }
    

    【讨论】:

    • 执行 std::async(std::launch::async, &Hello_class::hello, &hello_object);是调用成员函数的等价物吗?
    【解决方案3】:

    如果我们需要在第一个线程完成后开始运行第二个线程,真的需要线程吗?

    对于解决方案,我认为尝试设置一个全局标志,在第一个线程中设置值,然后在启动第二个线程时,首先检查标志应该有效。

    【讨论】:

    • 但是 - 只是为了挑剔 - 所有线程仍在运行,它们只是在等待条件发生。尽管如此 - 它们正在运行(从某种意义上说,它们是在 os 调度程序中调度的)。但没有其他解决方案。
    • 如果我们让多个任务等待这个。为什么不在完成第一个任务后创建线程。不要把它放在一个线程中。
    【解决方案4】:

    您不能像说“首先,线程 1,然后是线程 2,...”这样简单地控制顺序,您需要使用同步(即 std::mutex 和条件变量 std::condition_variable_any)。 您可以创建事件以阻塞一个线程,直到某个事件发生。

    请参阅cppreference,了解 C++-11 中的线程机制概述。

    【讨论】:

      【解决方案5】:

      您将需要使用信号量或锁。
      如果将信号量初始化为值 0:
      在 thread.start() 之后调用 wait 并在线程执行函数结束时调用 signal/release(例如 java 中的 run 函数、OnExit 函数等...)

      所以主线程会一直等待,直到循环中的线程完成执行。

      【讨论】:

        【解决方案6】:

        基于任务的并行性可以实现这一点,但 C++ 目前不提供任务模型作为其线程库的一部分。如果您有 TBB 或 PPL,您可以使用他们的基于任务的工具。

        【讨论】:

          【解决方案7】:

          我认为你可以通过使用 C++11 中的 std::mutexstd::condition_variable 来实现这一点。为了能够在使用的布尔数组中顺序运行线程,当线程完成一些工作时,它会在数组的特定索引中写入true。 例如:

          mutex mtx;
          condition_variable cv;
          int ids[10] = { false };
          
          void shared_method(int id) {
              unique_lock<mutex> lock(mtx);
          
              if (id != 0) {
                  while (!ids[id - 1]) {
                      cv.wait(lock);
                  }
              }
          
              int delay = rand() % 4;
              cout << "Thread " << id << " will finish in " << delay << " seconds." << endl;
              this_thread::sleep_for(chrono::seconds(delay));
          
              ids[id] = true;
              cv.notify_all();
          }
          
          void test_condition_variable() {    
              thread threads[10];
          
              for (int i = 0; i < 10; ++i) {
                  threads[i] = thread(shared_method, i);
              }
          
              for (thread &t : threads) {
                  t.join();
              }
          }
          

          输出:

          Thread 0 will finish in 3 seconds.
          Thread 1 will finish in 1 seconds.
          Thread 2 will finish in 1 seconds.
          Thread 3 will finish in 2 seconds.
          Thread 4 will finish in 2 seconds.
          Thread 5 will finish in 0 seconds.
          Thread 6 will finish in 0 seconds.
          Thread 7 will finish in 2 seconds.
          Thread 8 will finish in 3 seconds.
          Thread 9 will finish in 1 seconds.
          

          【讨论】:

            猜你喜欢
            • 2010-09-09
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-08-16
            • 2019-08-08
            • 1970-01-01
            相关资源
            最近更新 更多