47

在 C++03 中,我将 pthread 与自建线程池一起使用,该线程池始终保持几个线程运行(因为pthread_create速度很慢),这样我就能够为小任务启动线程,而无需考虑性能问题。

现在,在 C++11 中,我们有std::thread. 我想标准没有说明具体的实现,所以我的问题是关于标准库的实现。他们通常会选择构建std::threads 便宜(例如不调用pthread_createposix)的池化方法,还是std::thread只是一个包装器?

换句话说,在 C++11 中是否仍然推荐使用线程池,还是应该std::thread在需要时创建一个线程池并将性能留给标准库?

4

4 回答 4

32

通常,std::thread应该是底层系统原语的最小包装。例如,如果您在pthread平台上,您可以使用以下程序测试,无论您创建多少线程,它们都是使用唯一pthread_tid 创建的(这意味着它们是动态创建的,而不是从线程池中借用的):

#include <assert.h>
#include <mutex>
#include <set>
#include <thread>
#include <vector>

#include <pthread.h>

int main() {
  std::vector<std::thread> workers;
  std::set<long long> thread_ids;
  std::mutex m;
  const int n = 1024;

  for (int i = 0; i < n; ++i) {
    workers.push_back(std::thread([&] {
      std::lock_guard<std::mutex> lock(m);
      thread_ids.insert(pthread_self());
    }));
  }
  for (auto& worker : workers) {
    worker.join();
  }
  assert(thread_ids.size() == n);

  return 0;
}

所以线程池仍然很有意义。也就是说,我看过一个视频,其中 C++ 委员会成员讨论了有关std::async(IIRC) 的线程池,但我现在找不到它。

于 2012-10-20T23:36:54.557 回答
14

Astd::thread是一个执行线程。时期。它来自哪里,如何到达那里,是否有一些“实际”线程池等,都与标准无关。只要它的行为像一个线程,它就可以是一个std::thread.

现在,很有可能这std::thread是一个真实的操作系统线程,而不是从线程池或其他任何东西中提取的东西。但是 C++11 理论上确实允许 astd::thread被实现为从池中提取的东西。

于 2012-10-21T00:38:57.463 回答
5

std::thread就抽象成本而言,它应该非常便宜,它是低级的东西。据我了解,标准库实现可能只是尽可能紧密地包装底层操作系统机制,因此您可以假设线程创建的开销是相似或等效的。

我不知道任何具体的实现,但这是我从阅读C++ Concurrency In Action中获得的二手理解,该标准建议他们使用最有效的实用方法。作者当然似乎认为与 DIY 相比,成本或多或少可以忽略不计。

该库在概念上类似于 Boost,所以我想使用 Boost 实现得出一些结论不会太牵强。

基本上,我认为您的问题没有直接的答案,因为它没有具体说明。虽然在我看来,我们将更有可能看到非常薄的包装器实现,但我认为如果线程池提供了效率优势,我认为库编写者不会被限制使用线程池。

于 2012-10-20T23:15:31.843 回答
2

首先,正如您所提到的,C++ 标准基本上没有指定库实现。但是 C++ 标准库的实现者应该遵守“as-if”规则。

例如,这意味着无论是底层 API 的瘦包装器还是线程池等高效实现,构造函数的行为都std::thread应该像创建新线程一样。(这里,“线程”是指 C++11 规范中的抽​​象执行线程,而不是具体的 OS 原生线程)

关于线程池的实现;

  • C++ 编译器和库应正确处理 C++ 线程特定资源(即thread_local变量),并且它们应在运行时协同工作。
  • 即使满足上述条件,似乎也不可能与操作系统特定的线程资源(Windows 的 TLS、pthread 的 TSS 等)协同工作。

所以,我假设大多数std::thread实现只是底层线程 API 的包装。

于 2012-10-23T11:25:31.253 回答