Correcto. Lo que está haciendo en el primer caso es eludir la naturaleza de seguridad de subprocesos de rand_r
. Con muchas funciones no seguras para subprocesos, el estado persistente se almacena entre las llamadas a esa función (como la semilla aleatoria aquí).
Con la variante de seguridad de subprocesos, realmente proporciona datos de subproceso específicos (seed1
y seed2
) para garantizar que el estado no se comparte entre subprocesos.
Tenga en cuenta que esto no hace que los números sean verdaderamente aleatorios, simplemente hace que las secuencias sean independientes entre sí. Si los inicia con la misma semilla, probablemente obtendrá la misma secuencia en ambos hilos.
Por ejemplo, supongamos que obtiene una secuencia aleatoria 2, 3, 5, 7, 11, 13, 17 con una inicial semilla de 0. Con una semilla compartida, alternar llamadas a rand_r
desde dos subprocesos diferentes causar esto:
thread 1 thread 2
<--- 2
3 --->
<--- 5
7 --->
<--- 11
13 --->
<--- 17
y ese es el mejor de los casos - en realidad se puede encontrar que el estado compartido se corrompe ya que los cambios en él pueden no ser atómica.
Con el estado no compartido (con a
y b
que representa las dos fuentes distintas de los números aleatorios):
thread 1 thread 2
<--- 2a
2b --->
<--- 3a
3b --->
<--- 5a
5b --->
::
Algunas llamadas seguras para subprocesos que requieren para proporcionar el estado-hilo específico como éste, otros puede crear datos específicos de subprocesos bajo las carátulas (usando una ID de subproceso o información similar) para que nunca tenga que preocuparse por ello, y puede usar exactamente el mismo código fuente en entornos con subprocesos y sin subprocesos. Yo prefiero este último, simplemente porque me hace la vida más fácil.
material adicional para la pregunta Editado:
> If in thread 1, I need a random number between 1 to n, should I do '(rand_r(&seed1) % (n-1)) + 1', or there is other common way of doing this?
Suponiendo que desea un valor entre 1
y n
incluido, utilice (rand_r(&seed1) % n) + 1
. El primer bit le da un valor de 0
a n-1
inclusive, luego agrega 1 para obtener el rango deseado.
> Is it right or normal if the memory for the seed is dynamically allocated?
La semilla tiene que ser persistente, siempre y cuando usted lo está utilizando. Podría asignarlo dinámicamente en la secuencia, pero también podría declararlo en la función de nivel superior de la secuencia. En ambos casos, tendrá que comunicar la dirección a los niveles más bajos de alguna manera (a menos que su hilo sea solo esa función que es poco probable).
Puede pasarlo a través de las llamadas de función o configurar una matriz global de alguna manera donde los niveles inferiores pueden descubrir la dirección de inicialización correcta.
Como alternativa, ya que necesita una matriz global de todos modos, puede tener una matriz global de semillas en lugar de direcciones semilla, que los niveles inferiores podrían usar para descubrir su semilla.
Probablemente (en ambos casos de usar la matriz global) tenga una estructura con clave que contenga la ID de la cadena como la clave y la semilla que se utilizará. Luego tendría que escribir su propia rutinarand()
que localizó la semilla correcta y llamó al rand_r()
con eso.
Esto es por eso que prefiero las rutinas de la biblioteca que hacen esto debajo de las coberturas con datos específicos de subprocesos.
gracias! entonces, la mejor manera es usar diferentes semillas con diferentes valores iniciales para diferentes hilos, ¿verdad? – derrdji
Yo diría que generalmente, sí. Pero hay algunas situaciones en las que es posible que desee un estado compartido (primer diagrama en mi respuesta), en cuyo caso podría evitar la posibilidad de corrupción llamando 'rand_r' al _same_ pero protegido por un mutex. Lo único que no quiere hacer es inicializar ambas secuencias con la misma semilla, ya que las secuencias serían idénticas. – paxdiablo
sí, ¡gracias! Estaba a punto de preguntar si podía compartir uno y guardar la llamada rand_r con un bloqueo mutex. – derrdji