I want to pass in an arbitrary number of functions together with their arguments to a function called startThread
so that it can run them concurrently.
My code is below but obviously, it has syntactic errors:
#include <iostream>
#include <thread>
#include <chrono>
#include <vector>
#include <exception>
int test1( int i, double d )
{
// do something...
using namespace std::chrono_literals;
std::this_thread::sleep_for( 3000ms );
return 0;
}
int test2( char c )
{
// do something...
using namespace std::chrono_literals;
std::this_thread::sleep_for( 2000ms );
return 0;
}
template< class Fn, class... Args > // how should I write the template and startThread params to
int startThread( Fn&&... fns, Args&&... args ) // get arbitrary functions as threads and their own arguments?
{
std::vector< std::thread > threads;
threads.push_back( std::thread( test1, 2, 65.2 ) ); // how to automate the task of starting the
threads.push_back( std::thread( test2, 'A' ) ); // threads instead of writing them one by one?
std::cout << "synchronizing all threads...\n";
for ( auto& th : threads ) th.join();
return 0;
}
int main( )
{
int successIndicator { };
try
{
successIndicator = startThread( test1( 2, 65.2 ), test2( 'A' ) ); // what should be passed to startThread?
} // How to pass the arguments?
catch ( const std::exception& e )
{
successIndicator = -1;
std::cerr << e.what( ) << '\n';
}
return successIndicator;
}
Thanks in advance.
This is how I would do it, using a recursive template function. And std::async instead of std::thread
#include <future>
#include <chrono>
#include <thread>
#include <iostream>
void test1(int /*i*/, double /*d*/)
{
std::cout << "Test1 start\n";
std::this_thread::sleep_for(std::chrono::milliseconds(300));
std::cout << "Test1 done\n";
}
void test2(bool)
{
std::cout << "Test2 start\n";
std::this_thread::sleep_for(std::chrono::milliseconds(500));
std::cout << "Test2 done\n";
}
//-----------------------------------------------------------------------------
// Recursive template function that will start all passed functions
// and then waits for them to be finished one by one.
// this will still be limited by the slowest function
// so no need to store them in a collection or something
template<typename Fn, typename... Fns>
void run_parallel(Fn fn, Fns&&... fns)
{
// I prefer using std::async instead of std::thread
// it has a better abstraction and futures
// allow passing of exceptions back to the calling thread.
auto future = std::async(std::launch::async, fn);
// are there any more functions to start then do so
if constexpr (sizeof...(fns) > 0)
{
run_parallel(std::forward<Fns>(fns)...);
}
future.get();
}
//-----------------------------------------------------------------------------
int main()
{
std::cout << "main start\n";
// start all functions by creating lambdas for them
run_parallel(
[]() { test1(1, 1.10); },
[]() { test2(true); }
);
std::cout << "main done\n";
}