@@ -166,7 +166,8 @@ namespace
166
166
class ParallelLoopBodyWrapper : public cv ::ParallelLoopBody
167
167
{
168
168
public:
169
- ParallelLoopBodyWrapper (const cv::ParallelLoopBody& _body, const cv::Range& _r, double _nstripes)
169
+ ParallelLoopBodyWrapper (const cv::ParallelLoopBody& _body, const cv::Range& _r, double _nstripes) :
170
+ is_rng_used (false )
170
171
{
171
172
172
173
body = &_body;
@@ -181,13 +182,23 @@ namespace
181
182
pThreadRoot = cv::instr::getInstrumentTLSStruct ().pCurrentNode ;
182
183
#endif
183
184
}
184
- #ifdef ENABLE_INSTRUMENTATION
185
185
~ParallelLoopBodyWrapper ()
186
186
{
187
+ #ifdef ENABLE_INSTRUMENTATION
187
188
for (size_t i = 0 ; i < pThreadRoot->m_childs .size (); i++)
188
189
SyncNodes (pThreadRoot->m_childs [i]);
189
- }
190
190
#endif
191
+ if (is_rng_used)
192
+ {
193
+ // Some parallel backends execute nested jobs in the main thread,
194
+ // so we need to restore initial RNG state here.
195
+ cv::theRNG () = rng;
196
+ // We can't properly update RNG state based on RNG usage in worker threads,
197
+ // so lets just change main thread RNG state to the next value.
198
+ // Note: this behaviour is not equal to single-threaded mode.
199
+ cv::theRNG ().next ();
200
+ }
201
+ }
191
202
void operator ()(const cv::Range& sr) const
192
203
{
193
204
#ifdef ENABLE_INSTRUMENTATION
@@ -207,6 +218,9 @@ namespace
207
218
r.end = sr.end >= nstripes ? wholeRange.end : (int )(wholeRange.start +
208
219
((uint64)sr.end *(wholeRange.end - wholeRange.start ) + nstripes/2 )/nstripes);
209
220
(*body)(r);
221
+
222
+ if (!is_rng_used && !(cv::theRNG () == rng))
223
+ is_rng_used = true ;
210
224
}
211
225
cv::Range stripeRange () const { return cv::Range (0 , nstripes); }
212
226
@@ -215,6 +229,7 @@ namespace
215
229
cv::Range wholeRange;
216
230
int nstripes;
217
231
cv::RNG rng;
232
+ mutable bool is_rng_used;
218
233
#ifdef ENABLE_INSTRUMENTATION
219
234
cv::instr::InstrNode *pThreadRoot;
220
235
#endif
0 commit comments