<p>You need to implement your own RNG class and not use the clib RNG implementation that shares the state across threads. What I'm using is a simple &amp; efficient <a href="https://en.m.wikipedia.org/wiki/Multiply-with-carry" rel="nofollow noreferrer" title="multiply-with-carry">multiply-with-carry</a> RNG by George Marsaglia, that I initialize with a seed based on pixel coordinates (e.g. simple x+y*width) that I'm calculating (state per pixel instead of global state)</p>

CC BY-SA 3.0
2016-12-29T15:33:50.220Z
This is more than thread safety. A mutex would make any global RNG thread safe but still slow and unpredictable with multiple threads. Per-pixel seed is indeed the way to go for reproducibility, although per-thread state is enough to fix the performance problem.
Olivier
CC BY-SA 3.0
2016-12-29T15:51:48.517Z
With thread-safe I don't mean use of mutex etc. but just making of an RNG class that has no static members. The clib version is bad as it has a global state shared across threads. I'll fix the answer to be more clear
JarkkoL
CC BY-SA 3.0
2016-12-29T17:04:04.390Z
PBRT already [has that](https://github.com/mmp/pbrt-v2/blob/master/src/core/rng.h) so the problem is likely how it is used (shared ?). I unfortunately don't know the PBRT code well enough to know what's going on.
Olivier
CC BY-SA 3.0
2016-12-31T04:22:16.790Z
A thread-safe RNG is not enough because that it only solves the race condition. But it serializes the execution and cache invalidation will still be present.
Mary Chang
CC BY-SA 3.0
2016-12-31T04:48:29.783Z
I'm not suggesting thread-safe implentation of a RNG class but implemeting RNG class that you use thread-safely, by not sharing the state across threads.
JarkkoL
CC BY-SA 3.0
2016-12-29T14:46:19.280Z
2016-12-29T15:54:11.297Z
2016-12-29T15:54:11.297Z
JarkkoL
<p>I'm implementing my path tracer using C++ and OpenMP partially based on the design of <a href="https://users.cg.tuwien.ac.at/zsolnai/gfx/smallpaint/" rel="nofollow noreferrer">Small Paint</a> (using a globally available RND function to generate random floats) and <a href="https://github.com/mmp/pbrt-v2" rel="nofollow noreferrer">PBRTv2</a> (uses a single RNG across all threads). I notice that due to the fact there can can be multiple threads accessing the same RNG. Race condition and CPU cache invalidation will occur caused by the RNG writing to memory to store/update it's current state. Thus dragging the performance down and mess up the RNG(makes it unpredictable).</p>

<p>How come this is in one of the top grade educational renderer? Or it's just a minor issue that isn't important?<br>
If it's important, is there a known good way to fix this without breaking PBRT's rendering/threading architecture?</p>

<multithreading>
Avoiding CPU race condition/cache invalidation of RNG on multi thread path tracing
Mary Chang
# Avoiding CPU race condition/cache invalidation of RNG on multi thread path tracing

(Asked by: username_0 on 2016-12-29)

I'm implementing my path tracer using C++ and OpenMP partially based on the design of [Small Paint](https://users.cg.tuwien.ac.at/zsolnai/gfx/smallpaint/) (using a globally available RND function to generate random floats) and [PBRTv2](https://github.com/mmp/pbrt-v2) (uses a single RNG across all threads). I notice that due to the fact there can can be multiple threads accessing the same RNG. Race condition and CPU cache invalidation will occur caused by the RNG writing to memory to store/update it's current state. Thus dragging the performance down and mess up the RNG(makes it unpredictable).

How come this is in one of the top grade educational renderer? Or it's just a minor issue that isn't important?  
If it's important, is there a known good way to fix this without breaking PBRT's rendering/threading architecture?

**Tags:** multithreading


---

## 1 answers

### Answer by username_1 on 2016-12-29. Score: 3

You need to implement your own RNG class and not use the clib RNG implementation that shares the state across threads. What I'm using is a simple & efficient [multiply-with-carry](https://en.m.wikipedia.org/wiki/Multiply-with-carry "multiply-with-carry") RNG by George Marsaglia, that I initialize with a seed based on pixel coordinates (e.g. simple x+y\*width) that I'm calculating (state per pixel instead of global state)

> **Comments:**
> **username_2**: This is more than thread safety. A mutex would make any global RNG thread safe but still slow and unpredictable with multiple threads. Per-pixel seed is indeed the way to go for reproducibility, although per-thread state is enough to fix the performance problem.  
> **username_1**: With thread-safe I don't mean use of mutex etc. but just making of an RNG class that has no static members. The clib version is bad as it has a global state shared across threads. I'll fix the answer to be more clear  
> **username_2**: PBRT already [has that](https://github.com/mmp/pbrt-v2/blob/master/src/core/rng.h) so the problem is likely how it is used (shared ?). I unfortunately don't know the PBRT code well enough to know what's going on.  
> **username_0**: A thread-safe RNG is not enough because that it only solves the race condition. But it serializes the execution and cache invalidation will still be present.  
> **username_1**: I'm not suggesting thread-safe implentation of a RNG class but implemeting RNG class that you use thread-safely, by not sharing the state across threads.  

---

