Creating a thread taking way too long

Viewed 126

I'm experimenting with threads. My program is supposed to take a vector and sum it by breaking it down into different sections and creating a thread to sum each section. Currently, my vector has 5 * 10^8 elements, which should be easily handled by my pc. However, the creation of each thread (4 threads in my case) takes an insanely long time. I'm wondering why...?

#include <iostream>
#include <thread>
#include <vector>
#include <mutex>
#include <algorithm>
#include <numeric>
#include <ctime>

std::mutex m;
int ans = 0;

void sumPart(const std::vector<int>& v, int a, int b){
    std::lock_guard<std::mutex> guard(m);
    ans += std::accumulate(v.begin()+a, v.begin()+b, 0); 
}

void sum(const std::vector<int>& v){
    //threadCount is 4 on my pc
    int threadCount = std::max(2, (int)std::thread::hardware_concurrency()/2);
    int sz = v.size()/threadCount;
    std::vector<std::thread> threads;
    for(int i = 0; i < threadCount; i++){
        clock_t start = clock();
        threads.push_back(std::thread(sumPart, v, sz*i, sz*(i+1)));
        std::cout << "thread " << i+1 << " took "  << (clock()-start)/(CLOCKS_PER_SEC/1000) << " ms to create" << std::endl;
    }
    
    for(std::thread& t : threads){
        t.join();
    }
    //the leftovers
    ans += std::accumulate(v.begin()+(threadCount)*sz, v.end(), 0);
}

int main(){
    const int N = 5e8;
    std::vector<int> v(N);
    for(int i = 0; i < N; i++){
        v[i] = i;
    }

    sum(v);
    std::cout << ans << std::endl;
}

Output:

thread 1 took 681 ms to create
thread 2 took 824 ms to create
thread 3 took 818 ms to create
thread 4 took 814 ms to create
1711656320

Also, if I decrease the number of elements in vector, the time it takes to create each thread decreases as well, which is weird... (Also I know I'm getting int overflow but that's besides the point)

2 Answers
   std::thread(sumPart, v, sz*i, sz*(i+1))

Arguments to thread functions are copied, as part of creating the execution thread.

Even though sumPart takes it parameter by value v gets internally copied. copying a vector with 500000000 values will take a little bit of time.

You can use std::ref to effectively pass v by reference to your thread function. Note, as it has been mentioned, your lock will single-thread all of your execution threads. However they'll be started very quickly.

Code calculating sum of all elements of a vector using multiple threads can be improved.

It doesn't require mutex at all,
It doesn't require void sumPart(const std::vector<int>& v, int a, int b) wrapper function over std::accumulate,
It doesn't require to pass std::vector, passing iterators are enough.
See following code,

#include <iostream>

#include <atomic>
#include <future>

#include <vector>
#include <numeric>

long long int sum(std::vector<int>::const_iterator firstIt,
                  std::vector<int>::const_iterator lastIt){

    std::vector<std::future<long long int>> futureList;
    int elementCount = (lastIt - firstIt) / std::max<int>(
                2, std::thread::hardware_concurrency() / 2);

    std::vector<int>::const_iterator it = firstIt;
    auto accumulateFun = std::accumulate<std::vector<int>::const_iterator,
            long long int>;

    long long total = 0;

    while(lastIt - it > elementCount){

        futureList.emplace_back(std::async(std::launch::async, accumulateFun, it,
                                           it + elementCount, total));
        it += elementCount;
    }

    total += std::accumulate(it, lastIt, total);

    for(std::future<long long int>& f : futureList){

        total += f.get();
    }

    return total;
}

int main(int , char *[]){

    const int N = 5e8;
    std::vector<int> numList(N);

    std::iota(numList.begin(), numList.end(), 0);

    std::cout<< sum(numList.cbegin(), numList.cend()) << '\n';
}

Related