Search code examples
c++multithreadingc++11stdthread

std::thread constructor with no parameter


According to cppreference.com, the std::thread constructor with no parameter means:

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?
  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.
  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. Why is std::thread not designed in this way?

Solution

  • 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".

    • A thread of execution represents a flow of control through your program, probably corresponding to an OS thread managed by the kernel.
    • 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.
    • There is no such concept as a "thread function" in standard C++. Any function can be run in a new thread of execution by passing it to the constructor of a std::thread object.
    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. So you default construct it, and then later launch a new thread of execution and associate it with the std::thread member variable. 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.

    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. You assign another std::thread to it:

    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. You are requesting the runtime to create a new thread of execution, which will be managed by a std::thread object.

    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.

    Because you don't need it. You start new threads of execution by constructing a std::thread object with arguments. 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. Why std::thread is not designed in this way?

    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. 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). 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.