Top 21 C++ Multithreading Developer Interview Questions You Must Prepare 19.Mar.2024

As we'll see in a subsequent tutorial, the easiest and recommended way is to use "futures". However, you can still get the result of some calculation from a thread by either:

Passing reference to a result variable to the thread in which the thread stores the results

Store the result inside a class memeber variable of a function object which can be retrieved once the thread has finished executing.

A thread_local object comes into existence when a thread starts and is destroyed when the thread ends. Each thread has its own instance of a thread-Local object.

To fully understand the implications, let's look at an example- here we'll declare a global variable "globalvar" as thread_local. This'll give each thread it's own copy of globalVar and any modifications made to globalVar will only persist inside that particular thread.In the example below, each of the two threads are modifying globalVar – but they are not seeing each other's change, neither is the main thread.

#include "stdafx.h"

#include <string>

#include <thread>

#include <iostream>

#include <functional>

#include <mutex>

using namespace std;

thread_local int globalVar = 0;

mutex mu;

void PrettyPrint(int valueToPrint)

{

  lock_guard<mutex> lock(mu);

  cout << "Value of globalVar in thread " << this_thread::get_id() << " is " << globalVar << endl;

}

void thread_Local_Test_Func(int newVal)

{

  globalVar = newVal;

  PrettyPrint(globalVar);

}

int main()

{

  globalVar = 1;

  thread t1(thread_Local_Test_Func, 5);

  thread t2(thread_Local_Test_Func, 20);

  t1.join();

  t2.join();

  cout << "Value of globalVar in MAIN thread is " << globalVar << endl;

    return 0;

}

Here's the output of the program – you can see that the three threads (t1, t2 and MAIN) does not see each other's changes to globalVar.

Value of globalVar in thread 17852 is 5

Value of globalVar in thread 29792 is 20

Value of globalVar in MAIN thread is 1

Can you guess what the output will be if globalVar was not declared thread_local ? Here it is :

Value of globalVar in thread 27200 is 5

Value of globalVar in thread 31312 is 20

Value of globalVar in MAIN thread is 20

If the global value was not thread local, the change made by each thread will be persisted outside the thread – here the MAIN thread is feeling the effect  of the change made by t2 and hence printing "20" instead of "1".

C++11 gives unique ids to forked threads which can be retrieved using :

By calling the get_id() member function for a specific thread

By calling std::this_thread::get_id() for the currently executing thread

An example of both is given below:

#include "stdafx.h"

#include <string>

#include <thread>

#include <iostream>

#include <functional>

using namespace std;

void Count()

{

  for (int i = 0; i < 100; i++)

  {

    cout << "counter at: " << i << endl;

  }

}

int main()

{

thread t22(Count);

  //Get the ID of the t22 thread

  std::thread::id k = t22.get_id();

  cout << k << endl;

  //Get the ID of the MAIN Thread

  std::thread::id j = std::this_thread::get_id();

  cout << j << endl;

  return 0;

}

If I run this code, I can see the thread ids in "threads" and "locals" window. Also note that the thread name is almost useless.

However, the "Location" column can give an indication as to which thread is executing.

There are essentially four ways of creating a thread:

  • Create a thread with a function pointer
  • Create a thread with a function object
  • Create a thread with a lambda
  • Create a thread with a member function

#include "stdafx.h"

#include <thread>

#include <iostream>

using namespace std;

int main()

{

  thread t1([] {

    cout << "Launching Scud missile" << endl;

  });

  t1.join();

  return 0;

}

A call to std::thread::join() blocks until the thread on which join is called, has finished executing. In each of the examples above, the join() call ensures that the main method waits for the execution of the spawned threads to finish before it can exit the application.

On the other hand, if we do not call join() after creating a thread in the above case, the main function will not wait for the spawned thread to complete before it tears down the application. If the application tears down before the spawned thread finishes, it will terminate the spawned thread as well, even if it has not finished executing. This can leave data in a very inconsistent state and should be avoided at all cost.

C++11 provides a way to get a hint at the number of threads that can be run in parallel from an application – which most of the time coincides with the number of logical cores.

unsigned int n = std::thread::hardware_concurrency();

On my system with 12 logical cores, it returns @This me that I should not attempt to fork more than 12 threads in my application. Note that this is VC++ – other C++ compiler implementations might give different results

Yes ! You can just pass the function arguments to the thread constructor. The thread constructor is a variadic template, which me it can accept any number of arguments. Here's an example:

#include "stdafx.h"

#include <string>

#include <thread>

#include <iostream>

using namespace std;

void FireTorpedo(int numCities, string torpedoType)

{

  cout << "Firing torpedo " << torpedoType << " at" << numCities << " cities." << endl;

}

int main()

{

  thread t1(FireTorpedo, 3, "HungryShark");

  t1.join();

  return 0;

}

No – function objects are copied to the internal storage for the thread. If you need to execute the operation on a specific instance of the function object, you should use std::ref() from <functional> header to pass your function object by reference.

Just pass in the address of a function to the thread constructor. The thread will start executing the function immediately.

#include "stdafx.h"

#include <thread>

#include <iostream>

using namespace std;

void FireMissile()

{

  cout << "Firing sidewinder missile " << endl;

}

int main()

{

  //Creating a thread with a function pointer

  thread t1(FireMissile);

  t1.join();

  return 0;

}

We need to use std::ref() from the <functional> header. Consider the following code snippet and associated output.

#include "stdafx.h"

#include <string>

#include <thread>

#include <iostream>

#include <functional>

using namespace std;

void ChangeCurrentMissileTarget(string& targetCity)

{

  targetCity = "Metropolis";

  cout << " Changing The Target City To " << targetCity << endl;

}

int main()

{

  string targetCity = "Star City";

  thread t1(ChangeCurrentMissileTarget, std::ref(targetCity));

  t1.join();

  cout << "Current Target City is " << targetCity << endl;

  return 0;

}

OUTPUT:

Changing The Target City To Metropolis

Current Target City is Metropolis

Notice that the changes to "targetCity" made by the thread was preserved once the thread exited.

Yes – just like the previous case, you can pass the arguments needed by the lambda closure to the thread constructor.

auto LaunchTorpedoFunc = [](int numCities, string torpedoType) -> void { cout << "Firing torpedo " << torpedoType << " at" << numCities << " cities." << endl; };

thread t1(LaunchTorpedoFunc, 7, "Barracuda");

t1.join();

Use the <thread> header file

#include <thread>

Note: The thread functionality is defined in the "std" namespace.

#include "stdafx.h"

#include <thread>

#include <iostream>

using namespace std;

class Torpedo

{

public:

  void LaunchTorpedo()

  {

    cout << " Launching Torpedo" << endl;

  }

};

int main()

{

  //Execute the LaunchTorpedo() method for a specific Torpedo object on a seperate thread

  Torpedo torpedo;

  thread t1(&Torpedo::LaunchTorpedo, &torpedo);

  t1.join();

  return 0;

}

Note that here you're executing the LaunchTorpedo() method for a specific Torpedo object on a seperate thread. If other threads are accessing the same "torpedo" object, you'll need to protect the shared resources of that object with a mutex.

Oversubscription is a situation where more threads are vying for runtime than the underlying hardware can support. One of the biggest cost associated with multiple threads is that of context-switches that happens when the processor switches threads. Ideally, the you'd not want to create more threads than the hardware can support.

Create a function object "Missile" and pass it to the thread constructor.

#include "stdafx.h"

#include <thread>

#include <iostream>

using namespace std;

//Create the function object

class Missile

{

public:

  void operator() () const

  {

    cout << "Firing Tomahawk missile" << endl;

  }

};

int main()

{

  //Creating a thread with an function object

  Missile tomahawk;

  thread t1(tomahawk);

  t1.join();

  return 0;

}

Yes. std::thread object owns a resource, where the resource is a current thread of execution. You can call std::move to move the ownership of the underlying resource from one std::thread object to another. The question is – why would you want to do that? Here's a scenario:You want to write a function that creates a thread but does not want to wait for it to finish. Instead it wants to pass the thread to another function which will wait for the thread to finish and execute some action once the execution is done.

#include "stdafx.h"

#include <string>

#include <thread>

#include <iostream>

#include <functional>

using namespace std;

void FireHTTPGet()

{

std::this_thread::sleep_for(std::chrono::milliseconds(5000));

  cout << "Finished Executing HTTP Get"<< endl;

}

void ProcessHTTPResult(thread t1)

{

  t1.join();

  cout << "HTTP Get Thread Finished Executing - Processing Result Data!" << endl;

}

int main()

{

  thread t11(FireHTTPGet);

  thread t12(ProcessHTTPResult, std::move(t11));

  //Do bunch of other processing without waiting for t11 to finish - instead now we've shouldered off the 

  // responsibility of monitoring t11 thread to t12.

  //Finally wait for t12 to finish

  t12.join();

  return 0;

}

OUTPUT:

Finished Executing HTTP Get

HTTP Get Thread Finished Executing - Processing Result Data!

A call to join() blocks the caller thread. This is really bad in situations where the caller thread is a main UI thread – because if the UI thread blocks, the application will stop responding to user inputs which will make it seem hanged.

Another place where calling join() is not advisable is inside a main game loop. Calling join() can block update and rendering of the game scene and severly impact the user experience (it'll be like watching a You tube video on a dial up internet connection !).

You can make a std::thread run in the background by calling std::thread::detach() on it. Once detached, a thread continues to run in the background and cannot be communicated with or waited upon to complete. When you detach a thread, the ownership and control passes over to the C++ Runtime Library, which ensures that the resources allocated to the thread are deallocated once the thread exits.

Here's a contrived example. We have a Count() function that prints numbers 1 to 1000 on the screen. If we create a thread to run the function and detach the thread immediately, we'll not see any output – because the main thread terminates before the "Count" thread has had an opportunity to run. To see some of the output, we can put the main thread to sleep for 10 miliseconds which gives the "count" thread to send some of the output to the screen.

#include "stdafx.h"

#include

#include

#include

#include

using namespace std;

void Count()

{

  for (int i = 0; i < 100; i++)

  {

    cout << "counter at: " << i << endl;

  }

}

int main()

{

  thread t1(Count);

std::this_thread::sleep_for(std::chrono::milliseconds(10));

  t1.detach();

  return 0;

}

Yes ! A lambda closure is nothing but a variable storing a lambda expression. You can store a lambda in a closure if you intend to reuse the lambda expression at more than one place in your code.

#include "stdafx.h"

#include <thread>

#include <iostream>

using namespace std;

int main()

{

  // Define a lambda closure

  auto LaunchMissileFunc = []() -> void { cout << "Launching Cruiser Missile" << endl; };

  thread t1(LaunchMissileFunc);

  t1.join();

  return 0;

}

Thread function arguments are always pass by value, i.e., they are always copied into the internal storage for threads. Any changes made by the thread to the arguments passed does not affect the original arguments. For example, we want the "targetCity" to be modified by the thread but it never happens:

#include "stdafx.h"

#include <string>

#include <thread>

#include <iostream>

#include <functional>

using namespace std;

void ChangeCurrentMissileTarget(string& targetCity)

{

  targetCity = "Metropolis";

  cout << " Changing The Target City To " << targetCity << endl;

}

int main()

{

  string targetCity = "Star City";

  thread t1(ChangeCurrentMissileTarget, targetCity);

  t1.join();

  cout << "Current Target City is " << targetCity << endl;

  return 0;

}

OUTPUT:

Changing The Target City To Metropolis

Current Target City is Star City

Note that the "targetCity" variable is not modified.