std::thread 不带参数的构造函数

std::thread constructor with no parameter

根据cppreference.comstd::thread 没有参数的构造函数意味着:

Creates new thread object which does not represent a thread.

我的问题是:

  1. 为什么我们需要这个构造函数?如果我们使用这个构造函数创建一个thread,我们以后如何"assign"一个线程函数?
  2. 为什么我们没有一个 "run(function_address)" 方法,这样当构造时没有参数,我们可以为 thread 指定一个函数 "run"。
  3. 或者,我们可以构造一个带有可调用参数(函数、函子等)的thread,但稍后调用一个"run()"方法来实际执行线程。为什么std::thread不是这样设计的?

提供了默认构造函数,以便可以创建 "empty" thread 对象。并非所有 thread 个对象都会在构造所述对象时与执行线程相关联。考虑何时 thread 是某种类型的成员并且该类型具有默认构造函数。考虑另一种情况,thread 类型没有 "suspended" 线程的概念,即它不能在挂起状态下创建。

thread 类型没有某种 "run" 方法,因为最初的设计决策 (IIRC) 之一是 "strong" 与 thread对象和执行线程。允许 thread 为 "moved" 使该意图更清晰(在我看来)。因此,将 thread 对象的实例移动到 "empty" 对象比尝试 "run" 一个 thread.

更清晰

可以想象,您可以创建某种提供 "run" 方法的包装器 class,但我认为这可能是一个更窄的用例,可以是 解决了 API 的 std::thread class.

编辑: 也许让我们首先评论最后一部分:

3.2 Why std::thread is not designed in this way?

我不知道为什么(肯定有优点和缺点 - 请参阅 Jonathan Wakely 的回答以了解有关其背后理性的更多详细信息),但似乎 c++11 std::thread 是建模的比例如更接近 pthreads QT 或 Java 的 QThread/Thread classes,这可能是您混淆的根源。

关于您的其他问题:

1.1 why do we need this constructor?

您可能想要创建一个 std::thread 变量但不要直接启动线程(例如 class 成员变量或静态数组的元素,es 由 alangab 显示)。它与可以在没有文件名的情况下创建的 std::fstream 没有太大区别。

1.2 And if we create a thread using this constructor, how can we "assign" a thread function later?

例如:

std::thread myThread;

// some other code

myThread = std::thread(foo()); 
  1. Why don't we have a "run(function_address)" method so that when constructed with no parameter, we can specify a function to "run" for that thread.

我不知道,为什么要这样设计,但我看不出 run 方法与上述语法相比有什么好处。

3.1 Or, we can construct a thread with a callable parameter(function, functors, etc.) but call a "run()" method to actually execute the thread later.

您可以通过创建 lambda 或 std::function 对象来模拟这一点,并在您想要 运行 函数时创建线程。

auto myLambda = [=]{foo(param1, param2);};
// some other code
std::thread myThread(myLambda);

如果您想使用您描述的语法,我建议您编写自己的 Thread 包装器 class(应该只需要几十行代码)(可选)确保线程在包装器销毁时分离或连接,在我看来,这是 std::thread.

的主要问题

您的问题表明可能存在一些混淆,清楚地将 执行线程 的概念与 std::thread 类型的概念分开会很有帮助,并将两者都来自 "thread function".

的想法
  • 一个执行线程表示程序中的控制流,可能对应于内核管理的OS线程。
  • 类型 std::thread 的对象可以与 执行线程 相关联,或者它可以是 "empty" 并且不引用任何 执行线程.
  • 标准 C++ 中没有 "thread function" 这样的概念。通过将任何函数传递给 std::thread 对象的构造函数,可以在新的 执行线程 中 运行。
  1. why do we need this constructor?

构建不引用 执行线程 的空状态。您可能希望 class 的成员变量是 std::thread,但不想立即将其与 执行线程 相关联。所以你默认构造它,然后启动一个新的执行线程并将它与std::thread成员变量相关联。或者你可能想这样做:

std::thread t;
if (some_condition) {
  t = std::thread{ func1, arg1 };
}
else {
  auto result = some_calculation();
  t = std::thread{ func2, arg2, result };
}

默认构造函数允许创建对象 t,而无需启动新的 执行线程 直到需要。

And if we create a thread using this constructor, how can we "assign" a thread function later?

您 "assign" 使用 "assignment" :-)

但是你没有给它分配 "thread function",那不是 std::thread 的目的。您为其分配另一个 std::thread

std::thread t;
std::thread t2{ func, args };
t = std::move(t2);

考虑创建新的执行线程,而不是"assigning a thread function"。您不只是分配一个函数,这就是 std::function 的用途。您正在请求 运行 时间来创建一个新的 执行线程 ,它将由 std::thread 对象管理。

  1. Why don't we have a "run(function_address)" method so that when constructed with no parameter, we can specify a function to "run" for that thread.

因为你不需要它。您可以通过构造带参数的 std::thread 对象来启动新的执行线程。如果您希望该执行线程与现有对象相关联,那么您可以通过 move-assigning 或交换来实现。

  1. Or, we can construct a thread with a callable parameter(function, functors, etc.) but call a "run()" method to actually execute the thread later. Why std::thread is not designed in this way?

为什么要这样设计?

std::thread 类型用于管理 执行线程 不持有供以后使用的可调用对象。如果你想创建一个稍后可以在新的 执行线程 上 运行 的可调用对象,在 C++ 中有很多方法可以做到这一点(使用 lambda 表达式,或者std::bind,或 std::function,或 std::packaged_task,或自定义函子类型)。 std::thread 的工作是管理 执行线程 在你想调用它之前不要持有可调用对象。

默认构造函数让您可以创建线程数组:

thread my_threads[4];

for (int i=0; i<4; i++)
{
   thread temp(func,...);
   my_threads[i]=move(temp);
}

使用默认构造函数创建的线程 "become" 使用移动构造函数的 "real" 线程。

如果 need/like.

,您可以将线程与标准容器一起使用