Table of Contents

C - C++ Threads - Important Considerations - Thread function arguments are always passed by value

NOTE: Arguments are always copies into the internal storage for threads.

This means that any changes made by the thread to the arguments passed does not affect the original arguments.

  • The compiler may not even allow the compilation of the program.
  • To fix, ensure that arguments are passed by reference.

Example

#include <iostream>
#include <string>
#include <thread>
#include <functional>
 
 
void ChangeTotal(std::int& targetTotal)
{
  targetTotal = 20;
  std::cout << "Changing target_total to " << targetTotal << std::endl;
}
 
int main()
{
  int total = 10;
  std::thread t1(ChangeTotal, total);
  t1.join();
  std::cout << "Current Total is " << total << std::endl;
  return 0;
}

NOTE: Trying to compile this will fail with a message such as the following.

The reason for this is that the arguments being passed to ChangeTotal() are not being passed by reference.

/usr/include/c++/9/thread: In instantiation of ‘std::thread::thread(_Callable&&, _Args&& ...) [with _Callable = void (&)(int&); _Args = {int&}; <template-parameter-1-3> = void]:
test6.cpp:17:36:   required from here
/usr/include/c++/9/thread:120:44: error: static assertion failed: std::thread arguments must be invocable after conversion to rvalues
  120 |           typename decay<_Args>::type...>::value,
      |                                            ^~~~~
/usr/include/c++/9/thread: In instantiation of ‘struct std::thread::_Invoker<std::tuple<void (*)(int&), int> >:
/usr/include/c++/9/thread:131:22:   required from ‘std::thread::thread(_Callable&&, _Args&& ...) [with _Callable = void (&)(int&); _Args = {int&}; <template-parameter-1-3> = void]’
test6.cpp:17:36:   required from here
/usr/include/c++/9/thread:243:4: error: no type named ‘type’ in ‘struct std::thread::_Invoker<std::tuple<void (*)(int&), int> >::__result<std::tuple<void (*)(int&), int> >243 |    _M_invoke(_Index_tuple<_Ind...>)
      |    ^~~~~~~~~
/usr/include/c++/9/thread:247:2: error: no type named ‘type’ in ‘struct std::thread::_Invoker<std::tuple<void (*)(int&), int> >::__result<std::tuple<void (*)(int&), int> >247 |  operator()()
      |  ^~~~~~~~

Solution

Ensure that arguments are passed by reference:

#include <iostream>
#include <string>
#include <thread>
#include <functional>
 
 
void ChangeTotal(int& targetTotal)
{
  targetTotal = 20;
  std::cout << " Changing targetTotal to " << targetTotal << std::endl;
}
 
int main()
{
  int total = 10;
  std::thread t1(ChangeTotal, std::ref(total));
  t1.join();
  std::cout << "Total is " << total << std::endl;
  return 0;
}

NOTE: The std::ref changes the parameter to be passed by reference.