0

I am trying to create a C++ function that takes any function with any number of arguments and pass it to std::thread to start a thread with it.

#include <iostream>
#include <thread>

#define __PRETTY_FUNCTION__ __FUNCSIG__

void runFunctionInThread(void(*f)()) { std::thread t(f); t.join(); }
void runFunctionInThread(void(*f)(int), int value) { std::thread t(f, value); t.join(); }
void runFunctionInThread(void(*f)(int, int), int value1, int value2) { std::thread t(f, value1, value2); t.join(); }

void isolatedFunc1()                       { std::cout << __PRETTY_FUNCTION__ << "\n"; }
void isolatedFunc2(int value)              { std::cout << __PRETTY_FUNCTION__ << " value is " << value << "\n"; }
void isolatedFunc3(int value1, int value2) { std::cout << __PRETTY_FUNCTION__ << " value1+value2 is " << value1 + value2 << "\n"; }

int main() {

    runFunctionInThread(&isolatedFunc1);
    runFunctionInThread(&isolatedFunc2, 2);
    runFunctionInThread(&isolatedFunc3, 3, 3);
}

Is there anyway to create a single runFunctionInThread function that works for any function with any number of arguments and any type?

afp_2008
  • 1,940
  • 1
  • 19
  • 46
  • 3
    Use variadic templates for this – Remy Lebeau Dec 17 '20 at 19:24
  • 3
    Also [`std::packaged_task`](https://en.cppreference.com/w/cpp/thread/packaged_task) behaves this way. – Cory Kramer Dec 17 '20 at 19:25
  • 2
    Also, calling `join()` to wait on a thread immediately after creating the thread is a complete waste of the thread. `std::thread t(f(...)); t.join();` Would be no different than just calling `f(...)` by itself. You likely want to use `detach()` instead of `join()` – Remy Lebeau Dec 17 '20 at 19:27
  • 1
    @RemyLebeau Might be UB to use `std::cout` after `main` returns. `detach` is almost always problematic. – François Andrieux Dec 17 '20 at 19:40
  • 1
    @FrançoisAndrieux to work around that, you would have to save the `thread` objects you create, and then `join()` on them at a later time. – Remy Lebeau Dec 17 '20 at 19:47
  • Thank you for your comments folks. I know `std::thread` takes any function and arguments. However, `runFunctionInThread` does other stuff besides starting a thread. – afp_2008 Dec 17 '20 at 19:54

1 Answers1

1

Use a variadic template with perfect forwarding of its parameters, eg:

#include <iostream>
#include <thread>

#define __PRETTY_FUNCTION__ __FUNCSIG__

template<class Function, class... Args>
void runFunctionInThread(Function f, Args&&... args) {
    std::thread t(f, std::forward<Args>(args)...);
    t.detach();
}
 
void isolatedFunc1()                       { std::cout << __PRETTY_FUNCTION__ << "\n"; }
void isolatedFunc2(int value)              { std::cout << __PRETTY_FUNCTION__ << " value is " << value << "\n"; }
void isolatedFunc3(int value1, int value2) { std::cout << __PRETTY_FUNCTION__ << " value1+value2 is " << value1 + value2 << "\n"; }

int main()
{
    runFunctionInThread(&isolatedFunc1);
    runFunctionInThread(&isolatedFunc2, 2);
    runFunctionInThread(&isolatedFunc3, 3, 3);
}

However, this is fairly redundant since std::thread can handle this directly for you, so you don't need runFunctionInThread() at all, eg:

int main()
{
    std::thread(&isolatedFunc1).detach();
    std::thread(&isolatedFunc2, 2).detach();
    std::thread(&isolatedFunc3, 3, 3).detach();
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • Thank you for your great answer, exactly what I wanted. I know `std::thread` does this for me. However, `runFunctionInThread` does other stuff besides starting a thread. – afp_2008 Dec 17 '20 at 19:45
  • May I have your thoughts on this related question as well? https://stackoverflow.com/q/65347599/1227860 – afp_2008 Dec 17 '20 at 20:05
  • 1
    @AFPP You have already received plenty of good comments and answers on it – Remy Lebeau Dec 17 '20 at 20:41
  • @ Remy of course, based on your great, great solution. – afp_2008 Dec 17 '20 at 21:10
  • Hi Remy, I would truly appreciate your thoughts on this related question: https://stackoverflow.com/q/65352975/1227860 – afp_2008 Dec 18 '20 at 07:22