Ionut Alexandru
Ionut Alexandru

Reputation: 806

Multi threading sum

class Locker{
    mutex &m_mtx;
    public:
    Locker(mutex& mtx) : m_mtx{mtx}{m_mtx.lock();}
    ~Locker(){m_mtx.unlock();}
};
mutex mtx;
int globalOutput = 0;
void sum(const vector<int>& vect, int start, int end)
{
    for(auto i = vect.begin() + start; i != vect.begin() + end; ++i)
        {
            Locker{mtx};
            globalOutput+= *i;
        }
}

int main()
{
    const vector<int> vct(500, 2);

    thread th1(&sum, vct, 0, 250);
    thread th2(&sum, vct, 250, 500);

    th1.join();
    th2.join();

    std::cout << globalOutput;
}

I used a custom mutex class to synchronize two threads that calculate the sum of 500 items having the value 2. Do you know of another way to sync threads? Share knowledge, thank you!

Upvotes: 3

Views: 651

Answers (2)

AVH
AVH

Reputation: 11516

If the goal is to calculate the sum in parallel, but you don't actually care how it happens, you can also use std::reduce. Note that this requires C++17.

Using that your complete example code becomes:

int main () {
  const vector<int> vct(500, 2);
  auto sum = std::reduce(std::execution::par_unseq, vct.begin(), vct.end());
  std::cout << sum;
}

Upvotes: 2

jfMR
jfMR

Reputation: 24738

The statement Locker{mtx}; in:

{
   Locker{mtx};
   globalOutput+= *i;
}

creates an object Locker which locks the mutex mtx, but this object is destroyed right away and the mutex is unlocked. Therefore, globalOutput is modified by the thread while not holding a lock on the mutex. You may want instead:

{
   Locker locker{mtx};
   globalOutput+= *i;
   // locker object destroyed here
}

That is, you want to keep the lock on the mutex while modifying globalOutput.


Use std::lock_guard or std::scoped_lock

You can just use std::lock_guard instead of your custom Locker class:

{
   std::lock_guard<std::mutex> lck(mtx);
   globalOutput+= *i;
}

Since C++17 you can simply use std::scoped_lock, which renders std::lock_guard obsolete:

{
   // take advantage of C++17 template argument deduction for constructors
   std::scoped_lock lck(mtx);
   globalOutput+= *i;
}

Upvotes: 4

Related Questions