简体   繁体   English

没有参数的std :: thread构造函数

[英]std::thread constructor with no parameter

According to cppreference.com , the std::thread constructor with no parameter means: 根据cppreference.com ,没有参数的std::thread构造函数意味着:

Creates new thread object which does not represent a thread. 创建不代表线程的新线程对象。

My questions are: 我的问题是:

  1. Why do we need this constructor? 为什么我们需要这个构造函数? And if we create a thread using this constructor, how can we "assign" a thread function later? 如果我们使用这个构造函数创建一个thread ,我们如何在以后“分配”一个线程函数?
  2. 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(function_address)”方法,以便在没有参数构造时,我们可以为该thread指定一个“运行”的函数。
  3. Or, we can construct a thread with a callable parameter (function, functors, etc.) but call a "run()" method to actually execute the thread later. 或者,我们可以使用可调用参数(函数,函子等)构造一个thread ,但调用“run()”方法以便稍后实际执行该线程。 Why is std::thread not designed in this way? 为什么std::thread没有这样设计?

Your question suggests there might be some confusion and it would be helpful to clearly separate the ideas of a thread of execution from the std::thread type, and to separate both from the idea of a "thread function". 你的问题表明可能存在一些混淆,将std::thread类型的执行线程的思想清楚地分开,并将两者与“线程函数”的概念分开是有帮助的。

  • A thread of execution represents a flow of control through your program, probably corresponding to an OS thread managed by the kernel. 执行线程表示通过程序的控制流,可能对应于内核管理的OS线程。
  • An object of the type std::thread can be associated with a thread of execution , or it can be "empty" and not refer to any thread of execution . std::thread类型的对象可以与执行线程相关联,或者它可以是“空”而不是指任何执行线程
  • There is no such concept as a "thread function" in standard C++. 标准C ++中没有“线程函数”这样的概念。 Any function can be run in a new thread of execution by passing it to the constructor of a std::thread object. 任何函数都可以通过将它传递给std::thread对象的构造函数在新的执行线程中运行。
  1. why do we need this constructor? 为什么我们需要这个构造函数?

To construct the empty state that doesn't refer to a thread of execution . 构造不引用执行线程的空状态。 You might want to have a member variable of a class that is a std::thread , but not want to associate it with a thread of execution right away. 您可能希望拥有一个std::thread类的成员变量,但不想立即将它与执行线程相关联。 So you default construct it, and then later launch a new thread of execution and associate it with the std::thread member variable. 所以你默认构造它,然后启动一个新的执行线程并将它与std::thread成员变量相关联。 Or you might want to do: 或者您可能想要这样做:

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

The default constructor allows the object t to be created without launching a new thread of execution until needed. 默认构造函数允许在不需要启动新执行线程的情况下创建对象t

And if we create a thread using this constructor, how can we "assign" a thread function later? 如果我们使用这个构造函数创建一个线程,我们如何在以后“分配”一个线程函数?

You "assign" using "assignment" :-) 你使用“作业”“分配”:-)

But you don't assign a "thread function" to it, that is not what std::thread is for. 但是你没有给它分配一个“线程函数”,这不是std::thread的用途。 You assign another std::thread to it: 你为它分配另一个std::thread

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

Think in terms of creating a new thread of execution not "assigning a thread function" to something. 考虑创建一个新的执行线程而不是“为某个东西分配一个线程函数”。 You're not just assigning a function, that's what std::function would be used for. 你不只是分配一个函数,那就是std::function将用于什么。 You are requesting the runtime to create a new thread of execution , which will be managed by a std::thread object. 您正在请求运行时创建一个新的执行线程 ,该std::thread将由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. 为什么我们没有“run(function_address)”方法,以便在没有参数构造时,我们可以为该线程指定一个“运行”的函数。

Because you don't need it. 因为你不需要它。 You start new threads of execution by constructing a std::thread object with arguments. 您可以通过使用参数构造std::thread对象来启动新的执行std::thread If you want that thread of execution to be associated with an existing object then you can do that by move-assigning or swapping. 如果您希望该执行线程与现有对象相关联,则可以通过移动分配或交换来执行此操作。

  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. 或者,我们可以使用可调用参数(函数,函子等)构造一个线程,但调用“run()”方法以便稍后实际执行该线程。 Why std::thread is not designed in this way? 为什么std :: thread不是这样设计的?

Why should it be designed that way? 为什么要这样设计呢?

The std::thread type is for managing a thread of execution not holding a callable object for later use. std::thread类型用于管理不包含可调用对象的执行线程供以后使用。 If you want to create a callable object that can be later run on a new thread of execution there are lots of ways to do that in C++ (using a lambda expression, or std::bind , or std::function , or std::packaged_task , or a custom functor type). 如果你想创建一个可以在新的执行线程上运行的可调用对象,那么在C ++中有很多方法可以做到这一点(使用lambda表达式,或std::bind ,或std::function ,或std::packaged_task ,或自定义函子类型)。 The job of std::thread is to manage a thread of execution not to hold onto a callable object until you want to call it. std::thread的工作是管理一个执行线程,直到你想要调用它为止。

The default constructor is provided such that an "empty" thread object can be created. 提供默认构造函数,以便可以创建“空” thread对象。 Not all thread objects will be associated with a thread of execution at the time of construction of said object. 并非所有thread对象都与构造所述对象时的执行线程相关联。 Consider when the thread is a member of some type and that type has a default constructor. 考虑何时thread是某种类型的成员,并且该类型具有默认构造函数。 Consider another case that the thread type has no concept of a "suspended" thread, ie it can't be created in a suspended state. 考虑另一种情况,即thread类型没有“挂起”线程的概念,即它不能在挂起状态下创建。

The thread type doesn't have a "run" method of some sort since the one of the original design decisions (IIRC) was to have a "strong" association between the thread object and the thread of execution. thread类型没有某种“运行”方法,因为原始设计决策(IIRC)之一是在thread对象和执行线程之间建立“强”关联。 Allowing thread s to be "moved" makes that intent clearer (in my opinion). 允许thread被“移动”使得该意图更清晰(在我看来)。 Hence moving an instance of a thread object to an "empty" object is clearer than attempting to "run" a thread . 因此,将thread对象的实例移动到“空”对象比尝试“运行” thread更清楚。

It is conceivable that you can create a wrapper class of some sort that offers the "run" method, but I think this may be a narrower use case, and that can be solved given the API of the std::thread class . 可以想象你可以创建一个提供“run”方法的某种包装类,但我认为这可能是一个较窄的用例,并且可以std::thread类的API下解决

EDIT: Maybe lets firsts comment on the very last part: 编辑:也许让我们在最后一部分评论:

3.2 Why std::thread is not designed in this way? 3.2为什么std :: thread不是这样设计的?

I don't know why exactly (there are surely advantages and disatvantages - see Jonathan Wakely's answer for a more details about the rational behind it), but it seems that c++11 std::thread is modelled much closer to pthreads than eg QT's or Java's QThread/Thread classes, which might be the source of your confusion. 我不知道究竟是为什么(肯定有优点和缺点 - 请参阅Jonathan Wakely的答案,了解有关它背后的理性的更多细节),但似乎c ++ 11 std::thread的模型更接近pthreads而不是例如QT或Java的QThread/Thread类,可能是您混淆的根源。

As to the rest of your questions: 至于你的其他问题:

1.1 why do we need this constructor? 1.1为什么我们需要这个构造函数?

You might want to create a std::thread variable but don't directly start a thread (eg a class member variable or an element of a static array, es shown by alangab). 您可能想要创建一个std::thread变量,但不要直接启动一个线程(例如一个类成员变量或一个静态数组的元素,由alangab显示)。 It's not much different to an std::fstream that can be created without a filename. 与没有文件名创建的std::fstream没什么不同。

1.2 And if we create a thread using this constructor, how can we "assign" a thread function later? 1.2如果我们使用这个构造函数创建一个线程,我们如何在以后“分配”一个线程函数?

For example: 例如:

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(function_address)”方法,以便在没有参数构造时,我们可以为该线程指定一个“运行”的函数。

I don't know, why it was designed like this, but I don't see the benefit a run method would have compared to above syntax. 我不知道,为什么它是这样设计的,但是我没有看到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. 3.1或者,我们可以使用可调参数(函数,函子等)构造一个线程,但调用“run()”方法以便稍后实际执行该线程。

You can simulate this by creating a lambda or std::function object and create the thread when you want to run the function. 您可以通过创建lambda或std::function对象来模拟这一点,并在您想要运行该函数时创建该线程。

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

If you want to use the syntax you describe, I'd recommend to write your own Thread wrapper class (should only take a few dozen lines of code) that (optionally) also ensures that the thread is either detached or joined upon destruction of the wrapper, which is - in my opinion - the main problem with std::thread . 如果你想使用你描述的语法,我建议你编写自己的Thread包装器类(应该只需要几十行代码)(可选)确保线程在拆除时被分离或连接包装器,在我看来 - 这是std::thread的主要问题。

The default constructor gives you then possibility to create array of threads: 默认构造函数为您提供了创建线程数组的可能性:

thread my_threads[4];

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

the thread created with default costructor "become" a "real" thread with the move costructor. 使用默认的costructor创建的线程“成为”移动构造函数的“真实”线程。

You can use thread with standard container if you need/like. 如果需要/喜欢,可以使用标准容器的线程。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM