0
#include <iostream>
#include <thread>
    
class MyClass {
public:
    MyClass(int val) : val_(val) {}
    
    int val_{0};
};
    
void threadFunction(MyClass myObj) {
    // do something ...
}
    
int main() {
    MyClass obj(42);
 
    std::thread t1(threadFunction, obj); 
    std::thread t2([=]() {
        threadFunction(obj);
    });
    
    t1.join();
    t2.join();
    
    return 0;
}

In thread t1, I called threadfunction directly whereas in thread t2, I put the call of threadFunction in a lambda.

Are these two ways of thread creation equivalent?

9
  • I think t1 copies obj once (the function takes it by value) and t2 copies it twice (the lambda takes a copy and the function takes it by value again). Commented Apr 29, 2024 at 12:37
  • @mch there's an extra copy (on the calling thread) in std::thread::thread, so I think both involve 2 copies Commented Apr 29, 2024 at 12:39
  • If we forget about the possibly different copy/move operations, the program behaves the same, right? Commented Apr 29, 2024 at 12:43
  • @Mathieu if you ignore the copy/move issues, then yes. Commented Apr 29, 2024 at 12:49
  • @wohlstad AlthoughthreadFunctionaccepts by value, I could still capture by reference in the lambda [&] because the copy is made in the lambda. Makes sense? Commented Apr 29, 2024 at 12:53

1 Answer 1

2

The only difference between the alternatives is related to copies or moves of the MyClass obj object.

It can be observed by adding copy and move constructors with prints:

class MyClass {
public:
    MyClass(int val) : val_(val) {}

    MyClass(MyClass const & other)
    {
        std::cout << "copy\n";
        val_ = other.val_;
    }

    MyClass(MyClass && other)
    {
        std::cout << "move\n";
        val_ = other.val_;
    }

    int val_{0};
};

In the first case, the std::thread constructor will make a copy of obj, and then it will be moved when the function will be invoked by the new thread.

See demo1, with output:

copy
move

In the second case, there will be an additional copy when the lambda will be executed and will call threadFunction.

See demo2, with output:

copy
move
copy

A third alternaive is the use the lambda with capture by reference.
This will reduce it to only one copy (when the lambda will call threadFunction).

See demo3, with output:

copy

Note that this third option relies on the fact that obj is not destroyed while the thread is being launched (otherwise a race condition will occue). In your case it is OK because the threads are joined while obj is still alive.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.