I want to run two concurrent threads both of which call a function (e.g. void channel()
) and that function needs access to a few objects namely a std::random_device
, a PRNG engine, and two std::uniform_int_distribution
objects. However I am not sure where I should define each of these objects. 3 different options come to my mind:
- Globally
- Inside the
channel
function asthread_local
(this one seems more natural to me) - In the body of each of thread functions (i.e.
thread1
andthread2
) as automatic variables.
Which one is the most efficient and least problematic? And is there any other option that might be better?
Here's an MRE (link):
#include <chrono>
#include <random>
#include <thread>
#include <fmt/core.h>
#include <fmt/std.h>
using std::chrono_literals::operator""ms;
// globally defined
// extern thread_local std::random_device rand_dev;
// extern thread_local std::random_device rand_dev { };
void
channel( /*std::mt19937& mtgen*/ )
{
// inside the function as thread_local
thread_local std::random_device rand_dev { };
thread_local std::mt19937 mtgen { rand_dev( ) };
thread_local std::uniform_int_distribution uniform_50_50_dist { 1, 2 };
if ( uniform_50_50_dist( mtgen ) == 1 )
{
thread_local std::uniform_int_distribution<size_t> uniform_dist_for_bit_select { 0, 10 };
const auto random_index { uniform_dist_for_bit_select( mtgen ) };
std::this_thread::sleep_for( 100ms );
fmt::print( "thread: {} produced {}\n", std::this_thread::get_id( ),
random_index );
}
}
void thread1( )
{
// inside the actual thread as automatic storage duration
// std::random_device rand_dev { };
// std::mt19937 mtgen { rand_dev( ) };
for ( size_t count { }; count < 10; ++count )
{
channel( /*mtgen*/ );
}
}
void thread2( )
{
// inside the actual thread as automatic storage duration
// std::random_device rand_dev { };
// std::mt19937 mtgen { rand_dev( ) };
for ( size_t count { }; count < 5; ++count )
{
channel( /*mtgen*/ );
}
}
int main( )
{
std::jthread th1 { thread1 };
std::jthread th2 { thread2 };
}
Now I may have to mention that I want each thread to have a separate std::random_device
and a separate std::mt19937
engine so that I don't have to share them between threads (because that way I'll have to synchronize them using e.g. mutexes). Although I guess using a single std::random_device
is possible by locking its mutex with a std::scoped_lock
before accessing it via its call operator()
.
Aucun commentaire:
Enregistrer un commentaire