|
| 1 | +# Thread Safety in PocketSphinx |
| 2 | + |
| 3 | +## Random Number Generator Thread Safety |
| 4 | + |
| 5 | +PocketSphinx uses a Mersenne Twister random number generator for features like dithering in audio processing. Prior to version 5.0.4, this RNG used global state and was not thread-safe. |
| 6 | + |
| 7 | +### Thread-Local Storage Support |
| 8 | + |
| 9 | +Starting with version 5.0.4, PocketSphinx supports thread-local storage for the random number generator, making it thread-safe when enabled. |
| 10 | + |
| 11 | +#### Enabling Thread-Local RNG |
| 12 | + |
| 13 | +Thread-local storage is **enabled by default** when building with CMake on supported platforms: |
| 14 | + |
| 15 | +```bash |
| 16 | +cmake -DPS_THREAD_LOCAL_RNG=ON .. |
| 17 | +``` |
| 18 | + |
| 19 | +To explicitly disable it: |
| 20 | + |
| 21 | +```bash |
| 22 | +cmake -DPS_THREAD_LOCAL_RNG=OFF .. |
| 23 | +``` |
| 24 | + |
| 25 | +#### Platform Requirements |
| 26 | + |
| 27 | +Thread-local storage requires one of: |
| 28 | +- C11 compiler with `_Thread_local` support |
| 29 | +- C++11 compiler with `thread_local` support |
| 30 | +- GCC 3.3+ with `__thread` support |
| 31 | +- Visual Studio 2015+ with `__declspec(thread)` support |
| 32 | + |
| 33 | +Most modern compilers support thread-local storage. |
| 34 | + |
| 35 | +#### Behavior |
| 36 | + |
| 37 | +When thread-local storage is enabled: |
| 38 | +- Each thread maintains its own independent RNG state |
| 39 | +- Calling `genrand_seed()` in one thread does not affect other threads |
| 40 | +- Sequences generated in different threads are independent |
| 41 | +- Thread-safe without any locks or synchronization |
| 42 | + |
| 43 | +When thread-local storage is disabled: |
| 44 | +- RNG uses global state (legacy behavior) |
| 45 | +- **NOT thread-safe** - concurrent access causes race conditions |
| 46 | +- All threads share the same RNG state |
| 47 | + |
| 48 | +#### API Compatibility |
| 49 | + |
| 50 | +The API remains unchanged. Existing code continues to work: |
| 51 | + |
| 52 | +```c |
| 53 | +#include <pocketsphinx.h> |
| 54 | +#include "util/genrand.h" |
| 55 | + |
| 56 | +/* Seed the RNG */ |
| 57 | +genrand_seed(12345); |
| 58 | + |
| 59 | +/* Generate random numbers */ |
| 60 | +long value = genrand_int31(); /* [0, 2^31-1] */ |
| 61 | +double real = genrand_real3(); /* (0, 1) */ |
| 62 | +``` |
| 63 | +
|
| 64 | +#### Where RNG is Used |
| 65 | +
|
| 66 | +The random number generator is primarily used for: |
| 67 | +- **Audio dithering** in feature extraction (when dithering is enabled) |
| 68 | +- Other stochastic processes in speech recognition |
| 69 | +
|
| 70 | +Most applications don't need to interact with the RNG directly. |
| 71 | +
|
| 72 | +#### Migration Notes |
| 73 | +
|
| 74 | +For applications using PocketSphinx in multiple threads: |
| 75 | +1. Ensure you're building with `PS_THREAD_LOCAL_RNG=ON` (default) |
| 76 | +2. Be aware that each thread now has independent RNG state |
| 77 | +3. If you need reproducible sequences across threads, seed each thread explicitly |
| 78 | +
|
| 79 | +#### Testing Thread Safety |
| 80 | +
|
| 81 | +You can verify thread safety by running: |
| 82 | +```bash |
| 83 | +./test_genrand_thread_tls |
| 84 | +``` |
| 85 | + |
| 86 | +This test verifies that: |
| 87 | +- Each thread maintains independent RNG state |
| 88 | +- No collisions occur between thread sequences |
| 89 | +- Deterministic behavior is preserved within each thread |
0 commit comments