Move Semantics

Move Semantics and Threads

How can move semantics be used to efficiently transfer resources between threads?

Illustration representing computer hardware

Move semantics can be particularly useful when transferring resources between threads. When you want to pass an object from one thread to another, you typically want to avoid copying, as that could be expensive (especially for large objects) and could lead to race conditions if both threads try to access the same resource.

Instead, you can use move semantics to efficiently transfer ownership of the resource from one thread to the other. Once the resource is moved, the original thread no longer has access to it, preventing race conditions.

Here's an example using std::thread and std::unique_ptr:

#include <iostream>
#include <memory>
#include <thread>

using std::unique_ptr, std::thread;

class BigObject {
 public:
  BigObject() {
    std::cout << "BigObject constructed\n";
  }
  ~BigObject() {
    std::cout << "BigObject destroyed\n";
  }
  void DoSomething() {
    std::cout << "Doing something\n";
  }
};

void ThreadFunction(unique_ptr<BigObject> obj) {
  obj->DoSomething();  
}

int main() {
  unique_ptr<BigObject> obj{new BigObject{}};
  thread t{ThreadFunction, std::move(obj)};  

  t.join();
}
BigObject constructed
Doing something
BigObject destroyed

In this example, we create a BigObject managed by a unique_ptr in the main thread. We then create a new thread, passing the unique_ptr to the thread function using std::move(). This transfers ownership of the BigObject to the new thread.

Inside the thread function, we can use the BigObject safely, knowing that no other thread has access to it. When the thread function ends, the unique_ptr is destroyed, which in turn destroys the BigObject.

This pattern ensures that:

  1. There's no expensive copying of the BigObject.
  2. There are no race conditions, as only one thread owns the BigObject at a time.
  3. The BigObject is properly destroyed when it's no longer needed, regardless of how the thread ends.

The same pattern can be used with other types that support move semantics, such as std::string, std::vector, and many other standard library types.

Of course, this is just one way to use move semantics with threads. Depending on your specific use case, you might use move semantics with other thread synchronization primitives like std::promise and std::future, or with thread-safe queue types for passing messages between threads.

This Question is from the Lesson:

Move Semantics

Learn how we can improve the performance of our types using move constructors, move assignment operators and std::move()

Answers to questions are automatically generated and may not have been reviewed.

This Question is from the Lesson:

Move Semantics

Learn how we can improve the performance of our types using move constructors, move assignment operators and std::move()

A computer programmer
Part of the course:

Professional C++

Comprehensive course covering advanced concepts, and how to use them on large-scale projects.

Free, unlimited access

This course includes:

  • 125 Lessons
  • 550+ Code Samples
  • 96% Positive Reviews
  • Regularly Updated
  • Help and FAQ
Free, Unlimited Access

Professional C++

Comprehensive course covering advanced concepts, and how to use them on large-scale projects.

Screenshot from Warhammer: Total War
Screenshot from Tomb Raider
Screenshot from Jedi: Fallen Order
Contact|Privacy Policy|Terms of Use
Copyright © 2024 - All Rights Reserved