Skip to main content

Exploring Thread Creation in C++11 Using Callable Objects

Creating threads in C++11 provides the ability to execute multiple tasks simultaneously, which greatly improves the efficiency and responsiveness of your programs. In this comprehensive guide, we will delve into five different approaches to creating threads using callable objects. Each method will be explained in detail, accompanied by practical examples to illustrate their usage and benefits. By the end of this exploration, you will have a solid understanding of how to effectively manage concurrent execution in your C++11 applications.


1. Function Pointer

A function pointer is a straightforward method for creating a thread. You provide a function along with its arguments to the constructor.

Example:

#include <iostream>
#include <thread>

// Function to be executed by the thread
void fun(int x) {
    while (x++ < 15) {
        std::cout << x << std::endl;
    }
}

int main() {
    // Create a thread that runs the function 'fun' with argument 10
    std::thread t1(fun, 10);
    t1.join(); // Wait for the thread to finish
    return 0;
}

Explanation:

  • std::thread t1(fun, 10); creates a thread that runs the fun function with the argument 10.
  • t1.join(); ensures the main thread waits for t1 to finish before continuing.

2. Lambda Function

Lambda functions are anonymous functions that can be defined inline, making them useful for executing short and simple tasks.

Example:

#include <iostream>
#include <thread>

int main() {
    // Create a thread using a lambda function
    std::thread t( {
        while (x-- > 0) {
            std::cout << x << std::endl;
        }
    }, 10);
    t.join(); // Wait for the thread to finish
    return 0;
}

Explanation:

  • The lambda function { ... } is defined inline and passed to the thread.
  • t.join(); ensures the main thread waits for t to finish.

3. Functor (Function Object)

A functor is an object of a class that overloads the function call operator. This allows the object to be called like a function.

Example:

#include <iostream>
#include <thread>

// Functor class
class Base {
public:
    void operator()(int x) {
        while (x-- > 0) {
            std::cout << x << std::endl;
        }
    }
};

int main() {
    // Create a thread using a functor
    std::thread t(Base(), 10);
    t.join(); // Wait for the thread to finish
    return 0;
}

Explanation:

  • Base is a class with an overloaded operator().
  • std::thread t(Base(), 10); creates a thread that runs the operator() function of a Base object with the argument 10.

4. Non-Static Member Function

Non-static member functions need an instance of an object to be invoked.

Example:

#include <iostream>
#include <thread>

// Class with a non-static member function
class Base {
public:
    void run(int x) {
        while (x-- > 0) {
            std::cout << x << std::endl;
        }
    }
};

int main() {
    Base b;
    // Create a thread using a non-static member function
    std::thread t(&Base::run, &b, 10);
    t.join(); // Wait for the thread to finish
    return 0;
}

Explanation:

  • Base is a class with a member function run.
  • std::thread t(&Base::run, &b, 10); creates a thread that runs the run function of the Base object b with the argument 10.

5. Static Member Function

Static member functions do not need an instance of a class to be called; they can be invoked directly without creating an object.

Example:

#include <iostream>
#include <thread>

// Class with a static member function
class Base {
public:
    static void run(int x) {
        while (x-- > 0) {
            std::cout << x << std::endl;
        }
    }
};

int main() {
    // Create a thread using a static member function
    std::thread t(&Base::run, 10);
    t.join(); // Wait for the thread to finish
    return 0;
}

Explanation:

  • Base is a class with a static member function run.
  • std::thread t(&Base::run, 10); creates a thread that runs the static run function with the argument 10.

Conclusion

These five methods offer flexibility for creating threads in C++11. Depending on your specific needs, you can select the most appropriate approach.

When creating multiple threads at the same time, there is no guarantee that one will start before the others. Happy threading!



I hope this makes the concepts clearer and easier to understand! If you have any more questions or need further assistance, feel free to ask.

Comments

  1. Please write some blogs on javascript and react/next js aswell

    ReplyDelete

Post a Comment

Popular posts from this blog

Understanding push_back and emplace_back in C++

| Understanding push_back and emplace_back in C++ C++ provides several mechanisms to add elements to its containers, and two often used are push_back and emplace_back . Understanding the difference between these methods can help you write more efficient and expressive code. Let's delve into these concepts with examples to illustrate their usage and benefits.

constexpr in C++

|  Let’s dive into the depths of constexpr in C++! constexpr is short for "constant expression." It was introduced in C++11 and further enhanced in C++14 and C++20. The primary purpose of constexpr is to allow the evaluation of expressions at compile-time, enabling several powerful optimizations. Here’s a detailed breakdown: Purpose of constexpr The idea behind constexpr  is to inform the compiler that the value of a variable or the result of a function can be determined at compile-time. It will be if the expression can be evaluated at compile-time, resulting in performance benefits. It’s beneficial for: - Compile-time constants: Values that don’t change at runtime. - Optimizations: Allowing the compiler to optimize code more effectively. - Template metaprogramming: Enhancing the power of templates. Usage in Variables A constexpr  variable must be initialized with a constant expression.  Here’s an example: constexpr int length = 10; constexpr int width = 5; conste...

When do we use Initializer List in C++?

An initializer list is used to initialize the data members of a class. This list of members to be initialized is specified in the constructor as a comma-separated list, followed by a colon. Here is an example that demonstrates the use of an initializer list to initialize the variables x and y in the Point class. #include<iostream>  using namespace std;     class Point {  private:      int x;      int y;  public:      Point(int i = 0, int j = 0):x(i), y(j) {}       /*  The above use of the Initializer list is optional as the           constructor can also be written as:          Point(int i = 0, int j = 0) {              x = i;              y = j;          }      */              ...