C++ Library Extensions 2022.12.09
To help learn modern C++ programming
034-exception_safe.cpp
Go to the documentation of this file.
1#include <tpf_output.hpp>
2#include <tpf_safe_type.hpp>
4
5#include <execution> // for parallel algorithm
6
7/*
8 1. When we use Parallel Algorithm, we should NEVER leak exceptions
9 from the callback function used in the Parallel Algorithm.
10
11 2. Any callbacks used for the Parallel Algorithm, we always have to code
12 Multithread-Safe way. That is, we should prevent data race.
13
14 3. We should narrow down the locked region as small as possible, which
15 not only improve the performance of our program, but it also reduce
16 the potential of deadlock.
17*/
18
21
23{
24 size_t count = 10;
25 auto generator = tpf::chrono_random::random_generator<int>(0, (int)count);
26
27 std::vector<int> v; v.reserve(count);
28
29 // we initialize vector v with count of elements of type int
30 // with random numbers
31 for(size_t i=0; i < count; ++i)
32 v.emplace_back(generator());
33
34 stream << "Before: " << v << endl;
35
36 // we captured generator as reference, and it is shared
37 // among multiple threads, so we need to prevent
38 // data race using mutex and lock like this.
39
41
42 std::for_each(std::execution::par_unseq, v.begin(), v.end(),
43 [&generator, &mutex](auto& e)
44 {
45 // we divide each element of v
46 // with random integer
47
48 std::lock_guard<std::mutex> lock(mutex);
49 e /= generator();
50 } );
51
52 // In C++ Parallel Algorithm, if an exception leaks,
53 // our program chrashes. We have to preven
54 // exception leaks from our parallel algorithm by all means.
55 stream << "After: " << v << endl;
56}
57
59{
60 size_t count = 10;
61 auto generator = tpf::chrono_random::random_generator<int>(0, (int)count);
62
63 std::vector<int> v; v.reserve(count);
64
65 // we initialize vector v with count of elements of type int
66 // with random numbers
67 for(size_t i=0; i < count; ++i)
68 v.emplace_back(generator());
69
70 stream << "Before: " << v << endl;
71
72 // we have to treat the callback in the Parallel Algorithm
73 // as multithreaded function.
74
75 std::atomic<bool> operation_success{true};
77
78 std::for_each(std::execution::par_unseq, v.begin(), v.end(),
79 [&generator, &operation_success, &mutex](auto& e)
80 {
81 if(operation_success)
82 {
83 // we divide each element of v
84 // with random integer
85 std::unique_lock<std::mutex> lock(mutex);
86 auto d = generator();
87 lock.unlock();
88
89 if(d != 0)
90 e /= d;
91 else
92 operation_success = false;
93 }
94 } );
95
96 if(operation_success)
97 stream << "After: " << v << endl;
98 else
99 stream << "Parallel Algorithm Failed" << endl;
100}
101
103{
104 size_t count = 10;
105 auto generator = tpf::chrono_random::random_generator<int>(0, (int)count);
106
107 std::vector<int> v; v.reserve(count);
108
109 // we initialize vector v with count of elements of type int
110 // with random numbers
111 for(size_t i=0; i < count; ++i)
112 v.emplace_back(generator());
113
114 stream << "Before: " << v << endl;
115
116 // we have to treat the callback in the Parallel Algorithm
117 // as multithreaded function.
118
120 std::exception_ptr exception_ptr{nullptr};
121
122 // because exception_ptr and generator are
123 // shared among multiple threads,
124 // we have to prevent data race over these
125 // shared resource among multiple threads
126 std::for_each(std::execution::par_unseq, v.begin(), v.end(),
127 [&generator, &exception_ptr, &mutex](auto& e)
128 {
129 try
130 {
131 std::unique_lock<std::mutex> lock(mutex);
132 auto d = generator();
133
134 if(exception_ptr==nullptr)
135 {
136 lock.unlock();
137
138 e = tpf::safe_type::safe_div(e, d);
139 }
140 }
141 catch(...)
142 {
143 std::lock_guard<std::mutex> lock(mutex);
144 exception_ptr = std::current_exception();
145 }
146 } );
147
148 if(exception_ptr==nullptr)
149 stream << "After: " << v << endl;
150 else
151 {
152 std::rethrow_exception(exception_ptr);
153 }
154}
155
156int main()
157{
158 // problem_with_parallel_algorithm();
159 // safer_way_of_parallel_algorithm();
160
161 try
162 {
164 }
165 catch(const std::exception& e)
166 {
167 stream << "\n" << e << endl;
168 }
169
170 stream << "Now, our parallel algorithm works even if exception is thrown" << endl;
171}
std::mutex mutex
Definition: 022-mutex.cpp:12
std::atomic< int > count
Definition: 022-mutex.cpp:10
tpf::sstream stream
void safer_way_of_parallel_algorithm_using_exception()
void problem_with_parallel_algorithm()
void safer_way_of_parallel_algorithm()
auto endl
int main()
constexpr auto endl
Definition: tpf_output.hpp:973
Stream output operators << are implemented.
This file implements safe arithmetic.