vendredi 20 septembre 2019

Exception safety and concurrency in C++11 and beyond: guidelines for STL implemented functions

I am currently learning to handle concurrency in C++11 and beyond. As a reference, I chose a book called "C++ concurrency in action" which mentions that, when one designs parallel algorithms for, say, implementing a parallel accumulation of elements in a container, careful attention must be paid to the exception safety. Specifically, that the current struct:

template<typename Iterator,typename T>
struct accumulate_block
{
    void operator()(Iterator first,Iterator last,T& result)
    {
result=std::accumulate(first,last,result);
    }
};

if called upon in the below parallel function:

template<typename Iterator,typename T>
T parallel_accumulate(Iterator first,Iterator last,T init)
{
  // some code....
std::vector<T> results(num_threads);
std::vector<std::thread>  threads(num_threads-1);
Iterator block_start=first;
for(unsigned long i=0;i<(num_threads-1);++i)
    {
        Iterator block_end=block_start;
        std::advance(block_end,block_size);
        threads[i]=std::thread(
            accumulate_block<Iterator,T>(),
            block_start,block_end,std::ref(results[i]));
        block_start=block_end;
    }

 // more code...

}

It is argued that such code is not exception-safe because std::accumulate in the struct might throw, and proposes to use packaged_tasks and std::futures to haul exceptions between threads, rather than the above implementation.

My point is: how can I gauge which methods in the STL will throw, and how does "hauling" them inside futures and packaged_tasks make them any safer?

Thanks

Amine

Aucun commentaire:

Enregistrer un commentaire