您的问题表明可能存在一些混淆,将 执行线程 的概念与 std::thread 类型清楚地分开,并将两者与“线程函数”。
-
执行线程表示通过您的程序的控制流,可能对应于内核管理的操作系统线程。
-
std::thread 类型的对象可以与一个执行线程相关联,或者它可以是“空的”并且不引用任何执行线程。
- 标准 C++ 中没有“线程函数”这样的概念。通过将任何函数传递给
std::thread 对象的构造函数,任何函数都可以在新的执行线程中运行。
- 为什么我们需要这个构造函数?
构造不涉及执行线程的空状态。您可能希望拥有一个类的成员变量 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,而无需启动新的执行线程直到需要。
如果我们使用这个构造函数创建一个线程,我们以后如何“分配”一个线程函数呢?
您使用“分配”来“分配”:-)
但是您没有为其分配“线程函数”,这不是std::thread 的用途。你为它分配另一个std::thread:
std::thread t;
std::thread t2{ func, args };
t = std::move(t2);
考虑创建一个新的执行线程,而不是“分配一个线程函数”给某物。您不只是分配一个函数,这就是 std::function 的用途。您正在请求运行时创建一个新的执行线程,该线程将由std::thread 对象管理。
- 为什么我们没有一个“run(function_address)”方法,这样当不带参数构造时,我们可以指定一个函数来为那个线程“运行”。
因为你不需要它。您可以通过构造带有参数的std::thread 对象来启动新的执行线程。如果您希望该执行线程与现有对象相关联,则可以通过移动分配或交换来实现。
- 或者,我们可以构造一个带有可调用参数(函数、函子等)的线程,但稍后调用“run()”方法来实际执行该线程。为什么 std::thread 不是这样设计的?
为什么要这样设计?
std::thread 类型用于管理一个执行线程,该线程不持有供以后使用的可调用对象。如果您想创建一个可调用对象,以后可以在新的执行线程上运行,在 C++ 中有很多方法可以做到这一点(使用 lambda 表达式,或std::bind,或@987654336 @,或std::packaged_task,或自定义函子类型)。 std::thread 的工作是管理一个执行线程,在你想调用它之前不要持有一个可调用对象。