OVH Cloud OVH Cloud

random() et fork

26 réponses
Avatar
Axel
Salut

J essaie de faire generer des nombres aleatoires à X processus venant de
X fork() d'un processus père.

Quand chacun d'eux genere un nombre aleatoire avec random() ou rand(),
meme avec (1+(int) (10.0*rand()/(RAND_MAX+1.0))) , tous me renvoient la
meme valeur exactement.

Comment cela se fait il ?
Et comment avoir X processus générant des valeurs différentes ?

Merci d avance.

Axel

10 réponses

1 2 3
Avatar
kilobug

Salut


Salut

J essaie de faire generer des nombres aleatoires à X processus venant
de X fork() d'un processus père.


Quand chacun d'eux genere un nombre aleatoire avec random() ou rand(),
meme avec (1+(int) (10.0*rand()/(RAND_MAX+1.0))) , tous me renvoient
la meme valeur exactement.


C'est normal, random/rand utilisent un PRNG, c'est à dire une fonction
mathématique au comportement chaotique, mais cependant
déterministe. Les appels à srandom et srand permettent de changer la
"graine" de la fonction, en général on lui passe l'heure ou quelque
chose du même genre.

Si tu veux que le fils et le père soient différents, tu peux essayer
de regarder l'heure avant le fork, puis fait un srand/srandom avec
l'heure + le pid pour le père, et juste l'heure pour le fils (ou qqe
du genre).

Comment cela se fait il ?
Et comment avoir X processus générant des valeurs différentes ?


La seule solution plus ou moins portable que je voie consiste à
"bidouiller" comme expliqué plus haut pour faire un srandom différent
entre tous les processus.

Une autre solution est d'utiliser le générateur d'entropie du système
s'il y en a un (/dev/random et /dev/urandom sous Unix), afin de faire
le srand (pour des raisons de performances, accéder à /dev/urandom est
lent, et /dev/random ne doit être utilisé que si l'on a besoin
d'entropie cryptographiquement sûre)

En général, dans ce genre de cas, je fais un #ifdef HAVE_URANDOM, et
j'utilise le générateur du système si le programme est complié avec
cette option, et un classique time()+getpid() le reste du temps.

Merci d avance.


De rien

--
Gael Le Mignot "Kilobug" - - http://kilobug.free.fr
GSM : 06.71.47.18.22 (in France) ICQ UIN : 7299959
Fingerprint : 1F2C 9804 7505 79DF 95E6 7323 B66B F67B 7103 C5DA

Member of HurdFr: http://hurdfr.org - The GNU Hurd: http://hurd.gnu.org

Avatar
Emmanuel Delahaye
In 'fr.comp.lang.c', Axel wrote:

J essaie de faire generer des nombres aleatoires à X processus venant de
X fork() d'un processus père.

Quand chacun d'eux genere un nombre aleatoire avec random() ou rand(),
meme avec (1+(int) (10.0*rand()/(RAND_MAX+1.0))) , tous me renvoient la
meme valeur exactement.

Comment cela se fait il ?
Et comment avoir X processus générant des valeurs différentes ?


Il n'y a pas de 'processus' ou de 'fork()' en langage C. Merci de reposter
sur un forum dédié à ton système. Celui-ci a probalement un générateur de
random multi-processus. (au hasard : '/dev/random')

--
-ed- [remove YOURBRA before answering me]
The C-language FAQ: http://www.eskimo.com/~scs/C-faq/top.html
C-reference: http://www.dinkumware.com/manuals/reader.aspx?lib=cpp
FAQ de f.c.l.c : http://www.isty-info.uvsq.fr/~rumeau/fclc/

Avatar
kilobug

Il n'y a pas de 'processus' ou de 'fork()' en langage C. Merci de reposter
sur un forum dédié à ton système. Celui-ci a probalement un générateur de
random multi-processus. (au hasard : '/dev/random')


Attention, /dev/random n'est pas fait pour des simples nombres
aléatoires, il y a /dev/urandom pour cela. /dev/random renvoie de
l'entropie forte (= liée au matériel), qui se vide très vite, et
bloque le temps qu'il n'y a pas de nouveaux bits d'entropie
disponible... Il ne faut pas utiliser /dev/radom, à part dans une
application ayant vraiment besoin d'entropie (comme tout ce qui est
lié à la génération de clés en crypto, par exemple). Il y a
/dev/urandom qui génére des nombres aléatoires en grand quantité et
rapidement (modulo le coût de l'appel système).

Mais je suis d'accord, c'est HS.

--
Gael Le Mignot "Kilobug" - - http://kilobug.free.fr
GSM : 06.71.47.18.22 (in France) ICQ UIN : 7299959
Fingerprint : 1F2C 9804 7505 79DF 95E6 7323 B66B F67B 7103 C5DA

Member of HurdFr: http://hurdfr.org - The GNU Hurd: http://hurd.gnu.org

Avatar
Florent C.
Gaël Le Mignot wrote:

Mais je suis d'accord, c'est HS.



Je suis moyennement d'accord, l'histoire du fork() est certes HS, mais

il ne s'agit là que d'une petite partie de la question. Il est évident
que le problème d'Axel vient plus d'une mauvaise compréhension du
fonctionnement de rand() que de celui de fork().
Dans le doute, il a parlé des deux aspects de son programme, et c'est
normal.

Donc, si on évite d'être trop méchant, on lit complètement le post pour
isoler la vraie question avant de le classer HS. Et, personnellement, je
ne le classe pas HS du tout (mais cela n'engage que moi).

Florent.

Avatar
kilobug

Gaël Le Mignot wrote:
Mais je suis d'accord, c'est HS.




Je suis moyennement d'accord, l'histoire du fork() est certes HS,
mais il ne s'agit là que d'une petite partie de la question. Il est
évident que le problème d'Axel vient plus d'une mauvaise
compréhension du fonctionnement de rand() que de celui de fork().


Mwais, c'est vrai, mais les réponses (à base de getpid ou de
/dev/urandom) sont elles aussi HS ;)

Dans le doute, il a parlé des deux aspects de son programme, et c'est
normal.


Donc, si on évite d'être trop méchant, on lit complètement le post
pour isoler la vraie question avant de le classer HS.


Euh, j'ai répondu au post du mieux que je pouvais (donc je l'ai lu) et
je n'estime pas avoir été particulièrement méchant

Et, personnellement, je ne le classe pas HS du tout (mais cela
n'engage que moi).


Le post initial peut-être pas, mes réponses le sont ;) Mais je ne vois
pas comment répondre au post sans parler de choses non standards (au
sens standard du C, fork() est POSIX)

--
Gael Le Mignot "Kilobug" - - http://kilobug.free.fr
GSM : 06.71.47.18.22 (in France) ICQ UIN : 7299959
Fingerprint : 1F2C 9804 7505 79DF 95E6 7323 B66B F67B 7103 C5DA

Member of HurdFr: http://hurdfr.org - The GNU Hurd: http://hurd.gnu.org


Avatar
Pascal
Emmanuel Delahaye wrote:
Il n'y a pas de 'processus' ou de 'fork()' en langage C. Merci de reposter
sur un forum dédié à ton système. Celui-ci a probalement un générateur de
random multi-processus. (au hasard : '/dev/random')



Je suis en partie d'accord avec toi, mais une partie de sa question
traite du C. Tu as tendance a jouer au modérateur, mais la je trouve que
t'exagère. Je ne crois pas que son post pollue le ng, et je pense que
t'aurais pu t'abstenir de poster une réponse aussi inutile.
--
Pascal

Avatar
Alexandre Gouraud
Gaël Le Mignot wrote:
Le post initial peut-être pas, mes réponses le sont ;) Mais je ne vois
pas comment répondre au post sans parler de choses non standards (au
sens standard du C, fork() est POSIX)
Si on élimine le problème de fork(), qui n'est pas du C standard, et qui

n'est pas vraiment le problème, la fonction standard pour faire des
nombres aléatoires est rand() dont le prototype de fonction se trouve
dans stdlib.h, ou srand() (même header).

Si l'on souhaite obtenir une séquence aléatoire différente à chaque
appelle de srand(), il suffit d'utiliser une graine différente à chaque
fois. Pour cela, comme l'a proposé Gaël Le Mignot, il suffit d'utiliser
l'horloge du system, ou bien le nombre de "processor tics" depuis le
début de l'executions du programme. En C standard, un appel à time() ou
clock() (time.h) permet d'initialiser la graine.

PS : les fonctions time() et clock() ne fonctionnent pas forcément sur
tout les systèmes.

Alexandre.

Avatar
DINH Viêt Hoà

Emmanuel Delahaye wrote:
Il n'y a pas de 'processus' ou de 'fork()' en langage C. Merci de reposter
sur un forum dédié à ton système. Celui-ci a probalement un générateur de
random multi-processus. (au hasard : '/dev/random')


Je suis en partie d'accord avec toi, mais une partie de sa question
traite du C. Tu as tendance a jouer au modérateur, mais la je trouve que
t'exagère. Je ne crois pas que son post pollue le ng, et je pense que
t'aurais pu t'abstenir de poster une réponse aussi inutile.


Enfin je pense qu'en repostant sa question sur fr.comp.os.unix, il
aurait eu des réponses plus élaborée qu'ici.

--
DINH V. Hoa,

etPan! - newsreader, mail user agent -- http://libetpan.sf.net/etpan


Avatar
kilobug

Si l'on souhaite obtenir une séquence aléatoire différente à chaque
appelle de srand(), il suffit d'utiliser une graine différente à
chaque fois. Pour cela, comme l'a proposé Gaël Le Mignot, il suffit
d'utiliser l'horloge du system, ou bien le nombre de "processor tics"
depuis le début de l'executions du programme. En C standard, un appel
à time() ou clock() (time.h) permet d'initialiser la graine.


PS : les fonctions time() et clock() ne fonctionnent pas forcément sur
tout les systèmes.


Sauf que dans le cas de deux processus et d'un fork, time() est
souvent peu précis (time() aura souvent la même valeur dans le fils et
dans le père). Je ne connaissais pas clock(), mais en effet il est
précisé dans le man que ça peut renvoyer MAX-1 si le système ne
le supporte pas.

--
Gael Le Mignot "Kilobug" - - http://kilobug.free.fr
GSM : 06.71.47.18.22 (in France) ICQ UIN : 7299959
Fingerprint : 1F2C 9804 7505 79DF 95E6 7323 B66B F67B 7103 C5DA

Member of HurdFr: http://hurdfr.org - The GNU Hurd: http://hurd.gnu.org

Avatar
DINH Viêt Hoà

PS : les fonctions time() et clock() ne fonctionnent pas forcément sur
tout les systèmes.


Sauf que dans le cas de deux processus et d'un fork, time() est
souvent peu précis (time() aura souvent la même valeur dans le fils et
dans le père). Je ne connaissais pas clock(), mais en effet il est
précisé dans le man que ça peut renvoyer MAX-1 si le système ne
le supporte pas.


enfin même clock() peut éventuellement ne pas être assez précis suivant
la vitesse du système.

Enfin je pense qu'une combinaison d'un entier qui différencie
les 2 programmes (par exemple le pid comme tu l'as déjà proposé) plus
une valeur qui permet d'obtenir différentes valeurs (en moyenne) sur
deux exécutions de programme (par exemple l'heure comme tu l'as déjà
proposé) suffisent largement. Et cela apporte une portabilité suffisante
(on suppose déjà que fork() existe, donc à priori getpid() existe).

--
DINH V. Hoa,

etPan! - newsreader, mail user agent -- http://libetpan.sf.net/etpan


1 2 3