chiark / gitweb /
use thread-local storage for Mersenne twister to make thread-safe (for compilers...
authorstevenj <stevenj@alum.mit.edu>
Fri, 28 May 2010 21:41:12 +0000 (17:41 -0400)
committerstevenj <stevenj@alum.mit.edu>
Fri, 28 May 2010 21:41:12 +0000 (17:41 -0400)
darcs-hash:20100528214112-c8de0-4ca1313eec0a24eb1bc4e0b4aea0bc0c93c75788.gz

api/general.c
api/nlopt-internal.h
api/optimize.c
configure.ac
m4/ax_c_threadlocal.m4 [new file with mode: 0644]
util/mt19937ar.c

index 6ddd19ba140dc03bd4cbe1a833f8d280926ec8cf..c7f6a54c4eb665da4bac551cc2073b27d892200c 100644 (file)
@@ -102,7 +102,7 @@ const char *nlopt_algorithm_name(nlopt_algorithm a)
 
 /*************************************************************************/
 
-int nlopt_srand_called = 0;
+static THREADLOCAL int nlopt_srand_called = 0;
 void nlopt_srand(unsigned long seed) {
      nlopt_srand_called = 1;
      nlopt_init_genrand(seed);
@@ -112,4 +112,8 @@ void nlopt_srand_time() {
      nlopt_srand(nlopt_time_seed());
 }
 
+void nlopt_srand_time_default() {
+     if (!nlopt_srand_called) nlopt_srand_time();
+}
+
 /*************************************************************************/
index 67af6b1366abd7ac6f3856f9d70e1615bfd4f0fe..b0f16c64488bb3072f9a3806ddf3dc689291e0e0 100644 (file)
@@ -70,7 +70,7 @@ struct nlopt_opt_s {
 };
 
 /*********************************************************************/
-extern int nlopt_srand_called; /* whether the random seed is initialized */
+void nlopt_srand_time_default(void); /* init the rand. seed only if unset */
 
 /*********************************************************************/
 /* global defaults set by deprecated API: */
index 49595c005d764b988d004b740881e0f58379acf6..0877b01300f7cd8f7f203c80ab32c446b028fd26 100644 (file)
@@ -170,8 +170,7 @@ static nlopt_result nlopt_optimize_(nlopt_opt opt, double *x, double *minf)
      *minf = HUGE_VAL;
      
      /* make sure rand generator is inited */
-     if (!nlopt_srand_called)
-         nlopt_srand_time(); /* default is non-deterministic */
+     nlopt_srand_time_default(); /* default is non-deterministic */
 
      /* check bound constraints */
      for (i = 0; i < n; ++i)
index 800e96fe86b10b037da3a627d4dbc23638011190..fcf4b81569f421d2f4642ca08cbc219b66037fef 100644 (file)
@@ -44,6 +44,7 @@ AC_HEADER_TIME
 AC_CHECK_HEADERS([unistd.h getopt.h stdint.h])
 AC_C_CONST
 AC_C_INLINE
+AX_C_THREADLOCAL
 
 dnl find 32-bit unsigned integer type for random-number generator
 AC_CHECK_SIZEOF(unsigned int)
diff --git a/m4/ax_c_threadlocal.m4 b/m4/ax_c_threadlocal.m4
new file mode 100644 (file)
index 0000000..59c0c89
--- /dev/null
@@ -0,0 +1,39 @@
+dnl @synopsis AX_C_THREADLOCAL([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
+dnl @summary determine C keyword for threadlocal storage
+dnl
+dnl This macro tries to discover a C keyword to declare variables
+dnl as having thread-local storage.  Most commonly, this is either
+dnl __thread [gcc] or __declspec(thread) [Windows].
+dnl
+dnl On success, it #defines the THREADLOCAL preprocessor symbol to
+dnl the appropriate keyword.  You would then use it in C code as, e.g.:
+dnl     THREADLOCAL int myvariable;
+dnl
+dnl ACTION-IF-FOUND is a list of shell commands to run if an thread-local
+dnl keyword is found, and ACTION-IF-NOT-FOUND is a list of commands
+dnl to run it if one is not found.  If ACTION-IF-FOUND is not specified,
+dnl the default action does nothing.
+dnl
+dnl @version 2010-05-28
+dnl @license GPLWithACException
+dnl @author Steven G. Johnson <stevenj@alum.mit.edu>
+AC_DEFUN([AX_C_THREADLOCAL],
+[AC_CACHE_CHECK([for C thread-local keyword], acx_cv_c_threadlocal,
+[acx_cv_c_threadlocal=unsupported
+ AC_LANG_SAVE
+ AC_LANG_C
+ for acx_kw in __thread "__declspec(thread)"; do
+   AC_TRY_COMPILE([], [static $acx_kw int x = 0;], 
+                      [acx_cv_c_threadlocal=$acx_kw; break])
+ done
+ AC_LANG_RESTORE
+])
+ acx_kw="$acx_cv_c_threadlocal"
+ if test "$acx_kw" = unsupported; then acx_kw=""; fi
+ AC_DEFINE_UNQUOTED(THREADLOCAL, $acx_kw, [Define to C thread-local keyword, or to nothing if this is not supported in your compiler.])
+ if test "$acx_cv_c_threadlocal" = unsupported; then
+   m4_default([$2],:)
+ else
+   m4_default([$1],:)
+ fi
+])
index 54851294d07544e35a76b0f710097680bf06d3c1..f6d7f60fcb02dc05b7b3d4730186d8451cfe32aa 100644 (file)
 #define UPPER_MASK 0x80000000UL /* most significant w-r bits */
 #define LOWER_MASK 0x7fffffffUL /* least significant r bits */
 
-static uint32_t mt[N]; /* the array for the state vector  */
-static int mti=N+1; /* mti==N+1 means mt[N] is not initialized */
+/* SGJ 2010: make RNG thread-safe by declaring the RNG state as thread-local
+   storage, at least for GCC, MSVC, and Intel C++ */
+
+static THREADLOCAL uint32_t mt[N]; /* the array for the state vector  */
+static THREADLOCAL int mti=N+1; /* mti==N+1 means mt[N] is not initialized */
 
 /* initializes mt[N] with a seed */
 void nlopt_init_genrand(unsigned long s)