Skip to content

Commit 5ccafac

Browse files
committed
lib: correctly guard random number generation when run threaded
As random number generator tracks its internal state as a static variable, it is necessary to guard its updates with mutex to prevent misbehavour when multiple threads change values simultaneously
1 parent 85b38da commit 5ccafac

File tree

3 files changed

+43
-3
lines changed

3 files changed

+43
-3
lines changed

lib/gis/CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,13 @@ if(NOT WIN32)
44
list(FILTER gislib_SRCS EXCLUDE REGEX [[.*/fmode\.c$]])
55
endif()
66

7+
find_package(Threads)
8+
79
set(grass_gis_DEFS "-DGRASS_VERSION_DATE=\"${GRASS_VERSION_DATE}\"")
10+
if(Threads_FOUND)
11+
list(APPEND grass_gis_DEFS "HAVE_PTHREAD")
12+
endif()
13+
814
if(MSVC)
915
set(grass_gis_DEFS "${grass_gis_DEFS};-D_USE_MATH_DEFINES=1")
1016
set(gislib_INCLUDES "../../msvc")

lib/gis/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ MODULE_TOPDIR = ../..
22

33
LIB = GIS
44

5-
LIBES = $(OPENMP_LIBPATH) $(OPENMP_LIB)
5+
LIBES = $(OPENMP_LIBPATH) $(OPENMP_LIB) $(PTHREADLIB)
66
EXTRA_INC = $(ZLIBINCPATH) $(BZIP2INCPATH) $(ZSTDINCPATH) $(PTHREADINCPATH) $(REGEXINCPATH) $(OPENMP_INCPATH)
77
EXTRA_CFLAGS = $(OPENMP_CFLAGS) -DGRASS_VERSION_DATE=\"'$(GRASS_VERSION_DATE)'\"
88

lib/gis/lrand48.c

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@
33
*
44
* \brief GIS Library - Pseudo-random number generation
55
*
6-
* (C) 2014 by the GRASS Development Team
6+
* (C) 2014, 2025 by the GRASS Development Team
77
*
88
* This program is free software under the GNU General Public License
99
* (>=v2). Read the file COPYING that comes with GRASS for details.
1010
*
11-
* \author Glynn Clements
11+
* \authors Glynn Clements, Maris Nartiss (thread safety)
1212
*/
1313

1414
#include <stdio.h>
@@ -19,6 +19,10 @@
1919
#include <grass/gis.h>
2020
#include <grass/glocale.h>
2121

22+
#ifdef HAVE_PTHREAD
23+
#include <pthread.h>
24+
#endif
25+
2226
#ifdef HAVE_GETTIMEOFDAY
2327
#include <sys/time.h>
2428
#else
@@ -41,22 +45,36 @@ static const uint32 b0 = 0xB;
4145

4246
static int seeded;
4347

48+
#ifdef HAVE_PTHREAD
49+
static pthread_mutex_t lrand48_mutex = PTHREAD_MUTEX_INITIALIZER;
50+
#endif
51+
4452
#define LO(x) ((x) & 0xFFFFU)
4553
#define HI(x) ((x) >> 16)
4654

4755
/*!
4856
* \brief Seed the pseudo-random number generator
4957
*
5058
* \param[in] seedval 32-bit integer used to seed the PRNG
59+
*
60+
* This function is thread-safe.
5161
*/
5262
void G_srand48(long seedval)
5363
{
5464
uint32 x = (uint32) * (unsigned long *)&seedval;
5565

66+
#ifdef HAVE_PTHREAD
67+
pthread_mutex_lock(&lrand48_mutex);
68+
#endif
69+
5670
x2 = (uint16)HI(x);
5771
x1 = (uint16)LO(x);
5872
x0 = (uint16)0x330E;
5973
seeded = 1;
74+
75+
#ifdef HAVE_PTHREAD
76+
pthread_mutex_unlock(&lrand48_mutex);
77+
#endif
6078
}
6179

6280
/*!
@@ -65,6 +83,8 @@ void G_srand48(long seedval)
6583
* A weak hash of the current time and PID is generated and used to
6684
* seed the PRNG
6785
*
86+
* This function is thread-safe.
87+
*
6888
* \return generated seed value passed to G_srand48()
6989
*/
7090
long G_srand48_auto(void)
@@ -104,6 +124,10 @@ long G_srand48_auto(void)
104124

105125
static void G__next(void)
106126
{
127+
#ifdef HAVE_PTHREAD
128+
pthread_mutex_lock(&lrand48_mutex);
129+
#endif
130+
107131
uint32 a0x0 = a0 * x0;
108132
uint32 a0x1 = a0 * x1;
109133
uint32 a0x2 = a0 * x2;
@@ -123,11 +147,17 @@ static void G__next(void)
123147
x1 = (uint16)LO(y1);
124148
y2 += HI(y1);
125149
x2 = (uint16)LO(y2);
150+
151+
#ifdef HAVE_PTHREAD
152+
pthread_mutex_unlock(&lrand48_mutex);
153+
#endif
126154
}
127155

128156
/*!
129157
* \brief Generate an integer in the range [0, 2^31)
130158
*
159+
* This function is thread-safe.
160+
*
131161
* \return the generated value
132162
*/
133163
long G_lrand48(void)
@@ -142,6 +172,8 @@ long G_lrand48(void)
142172
/*!
143173
* \brief Generate an integer in the range [-2^31, 2^31)
144174
*
175+
* This function is thread-safe.
176+
*
145177
* \return the generated value
146178
*/
147179
long G_mrand48(void)
@@ -156,6 +188,8 @@ long G_mrand48(void)
156188
/*!
157189
* \brief Generate a floating-point value in the range [0,1)
158190
*
191+
* This function is thread-safe.
192+
*
159193
* \return the generated value
160194
*/
161195
double G_drand48(void)

0 commit comments

Comments
 (0)