Search code examples
c++11stdthread

Combining arrays from multiple threads using std::thread


I am writing a Monte Carlo program in C++ and am using std::thread to divide the number of histories to be tracked between the threads. However, this is my first attempt at multithreading and I have encountered a problem that this simplified code should hopefully let me demonstrate in the hopes that I can get some advice from the readers of this site. In this simplified problem, I am calling the function Summation that produces a 1X5 dimensional array of random numbers with 2 threads. When the threads return their values (not really returned since it is a global variable), the main program then has two five dimensional arrays, with each array corresponding to a different thread. I would like to combine the two arrays into a single array, with the elements in the final array, corresponding to the sum of the same elements in the two arrays that were produced by different threads. Unfortunately the arrays from each thread have the same name, so I can not simply add the two different arrays together. What methods are recommended to combine the two 1X5 dimensional arrays into a single summation array with elements corresponding to the sum of the identical elements from each thread?

#include <iostream>
#include <vector>
#include <thread>
#include <mutex>
#include <cassert>
#include "boost/multi_array.hpp"

std::vector<float> Array;
std::mutex Array_mutex;

void Summation(int sample_size)
{
    std::lock_guard<std::mutex> guard(Array_mutex);
    for(int i = 0; i < sample_size; i++)
    {
        Array.push_back(rand() % 10 + 1);
    }
    std::cout << "\n";
}

int main(int argc, const char * argv[]) {
    int sample_size = 10;
    int Num_Threads = 2;
    int number_count = sample_size/Num_Threads;
    srand(time(NULL));
    std::vector<std::thread> Threads;
    for(int i = 0; i < Num_Threads; i++)
    {
        Threads.push_back(std::thread(Summation,number_count));
    }

    for(int i = 0; i < Num_Threads; i++)
    {
        Threads[i].join();
    }

    // - I would like to combine the arrays produced from each thread into a
    //   single array, where each element in the final array is the sum of
    //   the identical element in the array from each thread

    // i.e. Element 1(final) = Element 1(thread 1) + Element 1(thread2)
    //      Element 2(final) = Element 2(thread 1) + Element 2(thread2)
    //      Element 3(final) = Element 3(thread 1) + Element 3(thread2)

    return 0;
}

Solution

  • If you want one vector per thread, you actually need to have one vector per thread. Like a vector of vectors.

    For a simple and naive solution, something like

    #include <iostream>
    #include <array>
    #include <random>
    #include <thread>
    
    void generate(const size_t size, std::array<float>& values)
    {
        // Pseudo-random number generation stuff
        std::random_device rd;
        std::default_random_engine e1(rd());
        std::uniform_int_distribution<float> uniform_dist(1, 10);
    
        // Generate some values and add the array
        for (size_t i = 0; i < size; ++i)
            values[i] = uniform_dist(el);
    }
    
    int main()
    {
        constexpr size_t number_values  = 10;
        constexpr size_t number_threads = 2;
    
        // An array of arrays, one sub-array per thread
        std::array<std::array<float, number_values>, number_threads>
            values;
    
        // An array of threads
        std::array<std::thread, number_threads> threads;
    
        // Create threads
        for (size_t i = 0; i < number_threads; ++i)
            threads[i] = std::thread(generate, number_values, std::ref(values[i]));
    
        // Wait for threads to finish
        for (size_t i = 0; i < number_threads; ++i)
            threads[i].join();
    
        // Now "combine" the values into a single array
        std::array<float, number_values> totals;
        for (size_t i = 0; i < number_values; ++i)
        {
            for (size_t j = 0; j < number_threads; ++j)
                totals[i] += values[j][i];
        }
    
        // Print the values
        for (const size_t i; i < number_values; ++i)
            std::cout << "Value #" << (i + 1) << " = " << totals[i] << '\n';
    }
    

    Note that the code is untested, and not even compiled, but should work in theory. :)