IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

 C Discussion :

rand() et pthread


Sujet :

C

  1. #1
    Membre confirmé
    Inscrit en
    Février 2008
    Messages
    67
    Détails du profil
    Informations forums :
    Inscription : Février 2008
    Messages : 67
    Par défaut rand() et pthread
    Hello,

    Soit le main() suivant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    int main(int argc, char* argv[])
    {
     pthread_t ta;
     pthread_t tb;
     pthread_create (&ta, NULL, task_a, NULL);
     pthread_create (&tb, NULL, task_b, NULL);
     srand (time(NULL));
     generenb(NOMBRE);
     #if 1
     pthread_join (ta, NULL);
     pthread_join (tb, NULL);
     #endif
     
     system("PAUSE");    
     return 0;
    }
    Dans la fonction que je duplique avec les thread, je génère une suite de nombre que je veux à chaque fois différente d'un thread à l'autre.

    Lorsque je n'ai qu'un seul thread (le a), la fonction generenb() ainsi que mon thread fonctionnent bien. Sur les deux "files", j'ai bien à chaque fois 2 nombres différents. Mais dès que je rajoute un deuxième thread, eh bien les nombres générés sont identiques (dans le thread a et b). A priori, ça me semble logique (vu que je lance une tache qui génère des nombres aléatoires, et rand() va générer dans les deux threads les même nombre).

    Bref, comment contourner mon problème ? de faire en sorte que, à partir de rand() :
    - threada => génère X
    - threadb => génère Y
    - fonction() => génère Z

    au lieu de

    - threada => génère X
    - threadb => génère X
    - fonction() => génère Z

    edit 1: Après réflexion, je me demandais s'il ne serait pas possible de rajouter à un argument à ma fonction generenb, qui serait une sorte de "grain de sel", argument que je changerais à chaque appele de ma fonction.

  2. #2
    Expert éminent
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 68
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Par défaut
    Citation Envoyé par nuitn0ire Voir le message
    Lorsque je n'ai qu'un seul thread (le a), la fonction generenb() ainsi que mon thread fonctionnent bien. Sur les deux "files", j'ai bien à chaque fois 2 nombres différents. Mais dès que je rajoute un deuxième thread, eh bien les nombres générés sont identiques (dans le thread a et b). A priori, ça me semble logique (vu que je lance une tache qui génère des nombres aléatoires, et rand() va générer dans les deux threads les même nombre).
    C'est aussi ce que je constate avec ce code basique :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
     
    #include <windows.h>
    #include <pthread.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
     
    void *task (void *puser)
    {
       int i;
       for (i = 0; i < 5; i++)
       {
          printf ("%s:%d\n", (char *) puser, rand ());
          Sleep (1);
       }
       return NULL;
    }
     
    int main (void)
    {
       srand (time (NULL));
       {
          pthread_t ta;
          pthread_t tb;
          pthread_create (&ta, NULL, task, (void *) "A");
          pthread_create (&tb, NULL, task, (void *) "B");
          pthread_join (ta, NULL);
          pthread_join (tb, NULL);
       }
       return 0;
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    A:41
    B:41
    A:18467
    B:18467
    A:6334
    B:6334
    A:26500
    B:26500
    A:19169
    B:19169
     
    Press ENTER to continue.
    C'est étrange. Il me semblait pourtant qu'il y a avait une statique pour rand() par procéssus, mais qu'il était commun aux tâches (threads).

    Ou pourrait effectivement démarrer chaque tâche avec un srand() différent...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
     
    #include <windows.h>
    #include <pthread.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
     
    void *task (void *puser)
    {
       int i;
       char const *s = puser;
     
       srand (time (NULL) + s[0]);
     
       for (i = 0; i < 5; i++)
       {
          printf ("%s:%d\n", s, rand ());
          Sleep (1);
       }
       return NULL;
    }
     
    int main (void)
    {
       {
          pthread_t ta;
          pthread_t tb;
          pthread_create (&ta, NULL, task, (void *) "A");
          pthread_create (&tb, NULL, task, (void *) "B");
          pthread_join (ta, NULL);
          pthread_join (tb, NULL);
       }
       return 0;
    }
    Ca marche :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    A:13289
    B:13293
    A:12938
    B:23687
    A:4678
    B:22542
    A:13224
    B:4519
    A:21361
    B:31676
     
    Press ENTER to continue.

  3. #3
    Membre confirmé
    Inscrit en
    Février 2008
    Messages
    67
    Détails du profil
    Informations forums :
    Inscription : Février 2008
    Messages : 67
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    #include <pthread.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <time.h>
     
    #define NOMBRE 100
     
    char genere(int nombre);
     
    static void *task_a (void *p_data)
    {
     char const *s = p_data;
     srand (time (NULL) + s[0]);
     genere(NOMBRE);   
     (void) p_data;
     return NULL;
    }
     
    static void *task_b (void *p_data)
    {
     char const *s = p_data;
     srand (time (NULL) + s[0]);
     genere(NOMBRE);             
     (void) p_data;
     return NULL;
    }
     
    int main(int argc, char* argv[])
    {
     pthread_t ta;
     pthread_t tb;
     pthread_create (&ta, NULL, task_a, NULL);
     pthread_create (&tb, NULL, task_b, NULL);
     #if 1
     pthread_join (ta, NULL);
     pthread_join (tb, NULL);
     #endif
     
     system("PAUSE");    
     return 0;
    }
     
    char genere(int nombre)
    {
     int i; 
     for (i = 0 ; i < NOMBRE ; i++)
      {
      int max2 = 100;
      int min2 = 1;
      int nb
      nb=min2+(int) (rand() % (max2+1-min2));                            
     }
    }
    violent plantage chez moi

  4. #4
    Membre confirmé
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    104
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Juin 2007
    Messages : 104
    Par défaut srand
    Oui, je crois savoir que le srand permet de generer des nombres aleatoires independants, pour chaque run du pgrm !
    rand ne fait que generer desnombres "pseudo-aleatoires" puisqu'ils seront tjs les memes apres chaque run ...


    (mais je crois que vous aviez trouve la soluce, deja)
    pepito

  5. #5
    Expert éminent
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 68
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Par défaut
    Citation Envoyé par nuitn0ire Voir le message
    <...>violent plantage chez moi
    Bah, oui. J'avais pourtant donné un exemple qui fonctionne...
    • Il n'y a besoin que d'une fonction 'thread'
    • Il faut apprendre à utiliser le 4ème paramètre de pthread_create(). Si tu passes NULL tu reçois NULL dans la tâche, logique... Déréférencement de NULL -> comportement indéterminé, tout peut arriver.

    Ceci fonctionne. Si tu ne comprends pas poses des questions, mais ne recopies pas sans comprendre...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
     
    #include <pthread.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <time.h>
     
    #define NOMBRE 10
     
    void genere (int nombre, char const *s)
    {
       int i;
       for (i = 0; i < nombre; i++)
       {
          int max = 100;
          int min = 1;
          int nb;
          nb = min + (int) (rand () % (max + 1 - min));
          printf ("%s: nb=%d\n", s, nb);
       }
    }
     
    static void *task (void *p_data)
    {
       char const *s = p_data;
       srand (time (NULL) + s[0]);
       genere (NOMBRE, s);
       return NULL;
    }
     
    int main (void)
    {
       pthread_t ta;
       pthread_t tb;
       pthread_create (&ta, NULL, task, (void *) "A");
       pthread_create (&tb, NULL, task, (void *) "B");
       pthread_join (ta, NULL);
       pthread_join (tb, NULL);
     
       return 0;
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
     
    A: nb=75
    A: nb=90
    A: nb=16
    A: nb=40
    A: nb=40
    A: nb=80
    A: nb=35
    A: nb=40
    B: nb=78
    B: nb=70
    B: nb=12
    B: nb=35
    B: nb=55
    B: nb=6
    B: nb=47
    B: nb=13
    B: nb=76
    B: nb=51
    A: nb=32
    A: nb=99
     
    Press ENTER to continue.
    Comme il n'y a pas de suspension explicite, c'est sans doute printf() (fonction I/O standard) qui fait office de 'scheduler' quand il peut... Dans mon code, il y a vait un Sleep(1) qui garantissait une juste répartition du temps entre les 2 tâches.

  6. #6
    Membre confirmé
    Inscrit en
    Février 2008
    Messages
    67
    Détails du profil
    Informations forums :
    Inscription : Février 2008
    Messages : 67
    Par défaut
    Eh bien écoute, je ne comprends pas.. Pas envie de passer pour un boulet, mais voici mon code complet :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    #include <pthread.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <time.h>
     
    #define NOMBRE 100
     
    char genereip(int nombreip);
     
    static void *task_a (void *p_data)
    {
     srand (time (NULL));
     genereip(NOMBRE);   
     (void) p_data;
     return NULL;
    }
     
    static void *task_b (void *p_data)
    {
     genereip(NOMBRE);             
     (void) p_data;
     return NULL;
    }
     
    int main(int argc, char* argv[])
    {
     pthread_t ta, tb;
     pthread_create (&ta, NULL, task_a, NULL);
     pthread_create (&tb, NULL, task_b, NULL);
     pthread_join (ta, NULL);
     pthread_join (tb, NULL);
     
     system("PAUSE");    
     return 0;
    }
     
    char genereip(int nombreip)
    {
     int i; 
     for (i = 0 ; i < NOMBRE ; i++)
      {
      int max2 = 1;
      int min2 = 100;
      int nb;
      nb=min2+(int) (rand() % (max2+1-min2));
      char ip[12];
      sprintf(ip,"192.168.1.%d",nb);
      printf("ip : %s\n",ip);
     }
    }
    Je comprends pas comment adapter ton code au mien. Par ailleurs, dans
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    pthread_create (&ta, NULL, task, (void *) "A");
    je ne comprends pas le "A".

    (bon, je débute en C, mais j'aimerais bien comprendre comment réorganiser mon code de façon à corriger mon problème).

    Voilà. Patapay.

  7. #7
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 397
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 397
    Par défaut
    Emmanuel: Pour rand(), ça dépend des implémentations.
    La C Run-Time Library (CRT) de Microsoft utilise une "graine" par thread, pour rester thread-safe: Aucun thread n'a d'influence sur les autres.

    D'ailleurs, c'est malin, le coup du srand(time(NULL)+valeur spécifique au thread). Je vais le garder sous la main, ce truc...
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  8. #8
    Expert éminent
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 68
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    Emmanuel: Pour rand(), ça dépend des implémentations.
    La C Run-Time Library (CRT) de Microsoft utilise une "graine" par thread, pour rester thread-safe: Aucun thread n'a d'influence sur les autres.
    OK, c'est pas idiot, surtout en cryptographie !

  9. #9
    Expert éminent
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 68
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Par défaut
    Citation Envoyé par nuitn0ire Voir le message
    Je comprends pas comment adapter ton code au mien.
    Déjà, il est incorrect :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
     
    Project   : Forums
    Compiler  : GNU GCC Compiler (called directly)
    Directory : C:\dev\forums\
    --------------------------------------------------------------------------------
    Switching to target: default
    Compiling: main.c
    main.c:25: warning: unused parameter 'argc'
    main.c:25: warning: unused parameter 'argv'
    main.c: In function `genereip':
    main.c:48: warning: too few arguments for format
    main.c: At top level:
    main.c:37: warning: unused parameter 'nombreip'
    main.c: In function `genereip':
    main.c:50: warning: control reaches end of non-void function
    Linking console executable: console.exe
    Process terminated with status 0 (0 minutes, 0 seconds)
    0 errors, 5 warnings
    Pourquoi tu crées 2 tâches. Les deux doivent avoir le même comportement, donc une seule suffit. Par contre, elles traiteront sans doute des données différentes, donc on passe un paramètre qui permet au moins de les différencier quand on fait un printf(), par exemple.
    est trop petit pour une adresse IP complète. Si tu ne sais pas compter (bienvenu au club!), tu fais comme ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
          char ip[sizeof "255.255.255.255"];
    tu es alors sûr d"avoir la bonne taille.

    Tu as choisi une plage d'IP étrange...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
      int max2 = 1;
      int min2 = 100;
    C'est voulu ?
    J'aurais dit :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
      int min = 1;
      int max = 100;
    et pourquoi se limiter à 100 ?
    Par ailleurs, dans
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    pthread_create (&ta, NULL, task, (void *) "A");
    je ne comprends pas le "A".

    (bon, je débute en C, mais j'aimerais bien comprendre comment réorganiser mon code de façon à corriger mon problème).
    As-tu lu la doc de pthread_create () ? As-tu compris à quoi servait le 4ème paramètre ?

    http://emmanuel-delahaye.developpez.com/pthreads.htm

    notamment le chapitre sur les données...

    Je propose ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
     
    #include <pthread.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <time.h>
     
    #include <windows.h>
     
    static char genereip (int nombreip, char const *s)
    {
       int i;
       for (i = 0; i < nombreip; i++)
       {
          int max = 254;
          int min = 2;
          int nb = min + (rand () % (max + 1 - min));
          char ip[sizeof "192.168.1.255"];
          sprintf (ip, "192.168.1.%d", nb);
          printf ("%s : ip : %s\n", s, ip);
          Sleep(1);
       }
    }
     
    static void *task (void *p_data)
    {
       char const *s = p_data;
     
       srand (time (NULL) + s[0]);
       genereip (100, s);
       return NULL;
    }
     
    int main (void)
    {
       pthread_t ta, tb;
       pthread_create (&ta, NULL, task, (void *) "alphonse");
       pthread_create (&tb, NULL, task, (void *) "beatrice");
       pthread_join (ta, NULL);
       pthread_join (tb, NULL);
     
       system ("PAUSE");
       return 0;
    }
    Pose des questions si tu ne comprends pas.

  10. #10
    Membre confirmé
    Inscrit en
    Février 2008
    Messages
    67
    Détails du profil
    Informations forums :
    Inscription : Février 2008
    Messages : 67
    Par défaut
    Re,

    Bon, ton code fonctionne, je l'ai adapté au mien, ça marche.

    mais !

    Si je rajoute un 3eme thread, j'ai nouveau mon problème de base, à savoir qu'il y a deux threads qui me renvoient le même résultat (problème que j'avais avec mon tout premier code). Avec un truc comme :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    /* [...] */
       pthread_t ta, tb, tc; 
       pthread_create (&ta, NULL, task, (void *) "alphonse");
       pthread_create (&tb, NULL, task, (void *) "beatrice");
       pthread_create (&tc, NULL, task, (void *) "test");   
       pthread_join (ta, NULL);
       pthread_join (tb, NULL);
       pthread_join (tc, NULL);
    /* [...] */
    Donc j'aimerais comprendre pourquoi et comment résoudre ce problème. Une fois résolu, j'aurai quelques petites questions..

    /edit : tant qu'à faire, je vais en profiter pour poser mes questions :

    1) La constante qu'on déclare dans la fonction (donc qui apparait en 4eme paramètre du pthread_create, c'est une variable qui sert uniquement à différencier les thread, de façon à ce que chacun d'eux ne fasse pas exactement la même chose, et donc nous renvoi une erreur à l'execution du programme ?

    2) J'imagine que cette approche des thread est simpliste (outre mon problème de rand), dans le code, on déclare les 2 ou 3 threads de cette façon dans le main, je me demandais si on ne pouvait pas faire une fonction dans laquelle on déclare simplement le nombre de thread que l'on veut et qui va se charger de nous les creer automatiquement. Un truc genre createthread(10) nous créerait 10 threads, au lieu de se cogner une succession de ligne comme on le fait là. Ce serait à mon sens plus propre et "pro".

  11. #11
    Expert éminent
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 68
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Par défaut
    Citation Envoyé par nuitn0ire Voir le message
    Si je rajoute un 3eme thread, j'ai nouveau mon problème de base, à savoir qu'il y a deux threads qui me renvoient le même résultat (problème que j'avais avec mon tout premier code). Avec un truc comme :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    /* [...] */
       pthread_t ta, tb, tc; 
       pthread_create (&ta, NULL, task, (void *) "alphonse");
       pthread_create (&tb, NULL, task, (void *) "beatrice");
       pthread_create (&tc, NULL, task, (void *) "test");   
       pthread_join (ta, NULL);
       pthread_join (tb, NULL);
       pthread_join (tc, NULL);
    /* [...] */
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    alphonse : ip : 192.168.1.32
    beatrice : ip : 192.168.1.35
    test : ip : 192.168.1.94
    alphonse : ip : 192.168.1.58
    beatrice : ip : 192.168.1.180
    test : ip : 192.168.1.79
    alphonse : ip : 192.168.1.35
    beatrice : ip : 192.168.1.58
    test : ip : 192.168.1.5
    alphonse : ip : 192.168.1.21
    beatrice : ip : 192.168.1.49
    test : ip : 192.168.1.243
    alphonse : ip : 192.168.1.174
    beatrice : ip : 192.168.1.116
    test : ip : 192.168.1.49
    alphonse : ip : 192.168.1.191
    beatrice : ip : 192.168.1.70
    test : ip : 192.168.1.155
    alphonse : ip : 192.168.1.92
    beatrice : ip : 192.168.1.37
    test : ip : 192.168.1.18
    alphonse : ip : 192.168.1.160
    beatrice : ip : 192.168.1.16
    test : ip : 192.168.1.211
    alphonse : ip : 192.168.1.77
    beatrice : ip : 192.168.1.143
    test : ip : 192.168.1.163
    alphonse : ip : 192.168.1.78
    beatrice : ip : 192.168.1.2
    test : ip : 192.168.1.169
    Appuyez sur une touche pour continuer...
    Je n'ai pas ce problème... Tu as du faire une erreur de codage quelque part...
    Donc j'aimerais comprendre pourquoi et comment résoudre ce problème. Une fois résolu, j'aurai quelques petites questions..
    Pour moi, le problème est résolu. Il suffit que la première lettre du nom soit différente des autres. Sinon, un peut utiliser un nombre
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
       pthread_t ta, tb, tc; 
     
       /* il faudrait vérifier qu'il n'y a pas de doublons, faire un tableau etc.  */
       int a=rand(), b=rand(), c=rand(); 
     
       pthread_create (&ta, NULL, task, &a);
       pthread_create (&tb, NULL, task, &b);
       pthread_create (&tc, NULL, task, &c);   
       <...>
    /edit : tant qu'à faire, je vais en profiter pour poser mes questions :

    1) La constante qu'on déclare dans la fonction (donc qui apparait en 4eme paramètre du pthread_create, c'est une variable qui sert uniquement à différencier les thread, de façon à ce que chacun d'eux ne fasse pas exactement la même chose,
    Oui. Je me sers de la valeur du premier caractère de la chaine pour srand(). Comme je l'ai montré au-dessus, des valeurs entières suffisent...
    et donc nous renvoi une erreur à l'execution du programme ?
    Euh, non aucun rapport. Ca sert à résoudre le problème de la suite de nombre qui est identique dans tous les threads. Là, je demande que les générateurs pseudo-aléatoires de chaque threads commencent à des valeurs différentes (graine ou seed, le 's' de srand()...).

    2) J'imagine que cette approche des thread est simpliste (outre mon problème de rand), dans le code, on déclare les 2 ou 3 threads de cette façon dans le main, je me demandais si on ne pouvait pas faire une fonction dans laquelle on déclare simplement le nombre de thread que l'on veut et qui va se charger de nous les creer automatiquement. Un truc genre createthread(10) nous créerait 10 threads, au lieu de se cogner une succession de ligne comme on le fait là. Ce serait à mon sens plus propre et "pro".
    - structure de données,
    - tableau de structure,
    - boucle...

    Rien que du C de base...

  12. #12
    Membre confirmé
    Inscrit en
    Février 2008
    Messages
    67
    Détails du profil
    Informations forums :
    Inscription : Février 2008
    Messages : 67
    Par défaut
    Ok, j'ai pigé l'histoire de la graine, j'avais mal compris le code à l'origine. Du coup ça fonctionne bien comme je veux, merci.

    Bon, j'ai essayé de trouver des infos concernant ma dernière requête, à savoir automatiser l'ouverture des threads que je répète. Ca donne ce code ci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     char datas[20][5];
     int i;
     pthread_t t[20];
     for(i=0;i<20;i++)
     {
      sprintf(datas[i],"%d",i);
      pthread_create (&t[i], NULL, task, (void *)datas[i]);  
      pthread_join (t[i], NULL);
     }
    Le hic, c'est que même si ce code se compile, malheureusement il ne me génère qu'un seul thread.. Et non 20 (comme dans mon exemple).

  13. #13
    Membre chevronné
    Profil pro
    Inscrit en
    Février 2008
    Messages
    439
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2008
    Messages : 439
    Par défaut
    Citation Envoyé par nuitn0ire Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     char datas[20][5];
     int i;
     pthread_t t[20];
     for(i=0;i<20;i++)
     {
      sprintf(datas[i],"%d",i);
      pthread_create (&t[i], NULL, task, (void *)datas[i]);  
      pthread_join (t[i], NULL);
     }
    Le hic, c'est que même si ce code se compile, malheureusement il ne me génère qu'un seul thread.. Et non 20 (comme dans mon exemple).
    Tu démarres un thread... et tu attends qu'il se termine juste après. Ton code génère bien 20 threads, mais 1 à la fois.

    Autant appeler directement task (data[i]) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     char datas[20][5];
     int i;
     for(i=0;i<20;i++)
     {
      sprintf(datas[i],"%d",i);
      task (data[i]);
     }

  14. #14
    Membre confirmé
    Inscrit en
    Février 2008
    Messages
    67
    Détails du profil
    Informations forums :
    Inscription : Février 2008
    Messages : 67
    Par défaut
    Problème résolu avec le code suivant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    char datas[NTHREAD][5];
    int i;
    pthread_t t[NTHREAD];
    for(i=0;i<NTHREAD;i++)
    {
     sprintf(datas[i],"%d",i);
     pthread_create (&t[i], NULL, task, (void *)datas[i]);
    }
     
    for(i=0;i<NTHREAD;i++)
    {
     pthread_join (t[i], NULL);
    }
    Cependant, la boucle qui est dans la fonction qu'elle mon thread ne s'arrête plus.. elle devait s'arrêter à un résultat de 100, là elle ne s'arrête plus..

    /edit : au temps pour moi, j'ai oublié que ma boucle bouclait NTHREAD fois ;p En fait ça marche.

    Merci à tous !

  15. #15
    Expert éminent
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 68
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Par défaut
    Citation Envoyé par nuitn0ire Voir le message
    Problème résolu avec le code suivant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    char datas[NTHREAD][5];
    int i;
    pthread_t t[NTHREAD];
    for(i=0;i<NTHREAD;i++)
    {
     sprintf(datas[i],"%d",i);
     pthread_create (&t[i], NULL, task, (void *)datas[i]);
    }
     
    for(i=0;i<NTHREAD;i++)
    {
     pthread_join (t[i], NULL);
    }
    Cependant, la boucle qui est dans la fonction qu'elle mon thread ne s'arrête plus.. elle devait s'arrêter à un résultat de 100, là elle ne s'arrête plus..

    /edit : au temps pour moi, j'ai oublié que ma boucle bouclait NTHREAD fois ;p En fait ça marche.

    Merci à tous !
    On peut aussi faire comme ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
     
    #include <pthread.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <time.h>
     
    #include <windows.h>
     
    static void genereip (int nombreip, int n)
    {
       int i;
       for (i = 0; i < nombreip; i++)
       {
          int max = 254;
          int min = 2;
          int nb = min + (rand () % (max + 1 - min));
          char ip[sizeof "192.168.1.255"];
          sprintf (ip, "192.168.1.%d", nb);
          printf ("%2d : ip : %s\n", n, ip);
          Sleep (1);
       }
    }
     
    static void *task (void *p_data)
    {
       int *pi = p_data;
       int n = *pi;
       srand (time (NULL) + n);
       genereip (10, n);
       return NULL;
    }
     
    int main (void)
    {
    #define NTHREAD 4
     
       int datas[NTHREAD];
       int i;
       pthread_t t[NTHREAD];
     
       for (i = 0; i < NTHREAD; i++)
       {
          datas[i] = i + 1;
          pthread_create (t+i, NULL, task, datas + i);
       }
     
       for (i = 0; i < NTHREAD; i++)
       {
          pthread_join (t[i], NULL);
       }
       return 0;
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
     
     1 : ip : 192.168.1.223
     2 : ip : 192.168.1.227
     3 : ip : 192.168.1.230
     4 : ip : 192.168.1.233
     1 : ip : 192.168.1.154
     2 : ip : 192.168.1.23
     3 : ip : 192.168.1.146
     4 : ip : 192.168.1.137
     1 : ip : 192.168.1.213
     2 : ip : 192.168.1.114
     3 : ip : 192.168.1.137
     4 : ip : 192.168.1.39
     1 : ip : 192.168.1.240
     2 : ip : 192.168.1.15
     3 : ip : 192.168.1.166
     4 : ip : 192.168.1.63
     1 : ip : 192.168.1.13
     2 : ip : 192.168.1.77
     3 : ip : 192.168.1.18
     4 : ip : 192.168.1.213
     1 : ip : 192.168.1.95
     2 : ip : 192.168.1.226
     3 : ip : 192.168.1.105
     4 : ip : 192.168.1.237
     1 : ip : 192.168.1.177
     2 : ip : 192.168.1.253
     3 : ip : 192.168.1.77
     4 : ip : 192.168.1.153
     1 : ip : 192.168.1.14
     2 : ip : 192.168.1.123
     3 : ip : 192.168.1.231
     4 : ip : 192.168.1.87
     1 : ip : 192.168.1.113
     2 : ip : 192.168.1.180
     3 : ip : 192.168.1.115
     4 : ip : 192.168.1.182
     1 : ip : 192.168.1.88
     2 : ip : 192.168.1.12
     3 : ip : 192.168.1.189
     4 : ip : 192.168.1.244
     
    Press ENTER to continue.

  16. #16
    Membre confirmé
    Inscrit en
    Février 2008
    Messages
    67
    Détails du profil
    Informations forums :
    Inscription : Février 2008
    Messages : 67
    Par défaut
    Encore deux questions :

    Est-ce qu'il est possible de mettre moins d'une seconde au srand(). J'entends par là que srand() modifie le grain toutes les secondes, mais j'ai l'impression que lorsque je mets trop de thread (ici plus de 10), j'ai des doublons qui apparaissent. Ca me semble logique dans la mesure où le srand() ne modifie pas assez vite la graine, dans ce cas un ou deux thread récupérerons la même graine, du coup => doublons.

    Es-ce qu'il y a une limite à ne pas dépasser dans l'utilisation des thread ? Par exemple une limite qui, si elle est dépassée, peu rendre notre programme instable.

  17. #17
    Expert éminent
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 68
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Par défaut
    Citation Envoyé par nuitn0ire Voir le message
    Est-ce qu'il est possible de mettre moins d'une seconde au srand(). J'entends par là que srand() modifie le grain toutes les secondes,
    Euh, non... srand() ne modifie la graine que si on lui demande...
    mais j'ai l'impression que lorsque je mets trop de thread (ici plus de 10), j'ai des doublons qui apparaissent. Ca me semble logique dans la mesure où le srand() ne modifie pas assez vite la graine, dans ce cas un ou deux thread récupérerons la même graine, du coup => doublons.
    C'est gênant ? J'ai un peu du mal à voir ce que tu veux faire...
    Es-ce qu'il y a une limite à ne pas dépasser dans l'utilisation des thread ? Par exemple une limite qui, si elle est dépassée, peu rendre notre programme instable.
    Il y a certainement une limite, mais je suppose qu'elle dépend du système...

    http://sourceware.org/pthreads-win32/

    etc. est ton ami...

  18. #18
    Membre chevronné
    Profil pro
    Inscrit en
    Février 2008
    Messages
    439
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2008
    Messages : 439
    Par défaut
    Citation Envoyé par Emmanuel Delahaye Voir le message
    Euh, non... srand() ne modifie la graine que si on lui demande...
    Oui, mais l'idiome classique :
    génère la même graine s'il est appelé plusieurs fois en moins d'une seconde, et je crois que c'est (presque) ce que nuitn0ire a voulu dire.

    C'est parfois un problème quand on peut lancer très vite plusieurs fois un programme, par exemple à partir d'un script.

  19. #19
    Membre chevronné
    Profil pro
    Inscrit en
    Février 2008
    Messages
    439
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2008
    Messages : 439
    Par défaut
    Citation Envoyé par Emmanuel Delahaye Voir le message
    C'est étrange. Il me semblait pourtant qu'il y a avait une statique pour rand() par procéssus, mais qu'il était commun aux tâches (threads).
    C'est quand même mieux d'avoir chaque thread qui peut appeler indépendament rand(), que d'avoir à protéger l'appel par un mutex!

    Citation Envoyé par Emmanuel Delahaye Voir le message
    Ou pourrait effectivement démarrer chaque tâche avec un srand() différent...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    void *task (void *puser)
    {
       char const *s = puser;
     
       srand (time (NULL) + s[0]);
    ...
     
          pthread_create (&ta, NULL, task, (void *) "A");
          pthread_create (&tb, NULL, task, (void *) "B");
    Si les threads sont lancés suffisamment vite, alors ça marche.

    Si le "A" démarre seulement 1 seconde après (en réalité, dans la seconde suivante) le "B", ça marche plus. Le cas va rarement se présenter, mais il est tout à fait possible.

    Ce n'est donc pas une solution.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Pthread et semaphores
    Par Yabo dans le forum Linux
    Réponses: 9
    Dernier message: 30/03/2008, 00h09
  2. Pb de rand() qui tourne en boucle
    Par MadChris dans le forum MFC
    Réponses: 3
    Dernier message: 26/06/2004, 16h24
  3. Probleme de tirage avec rand ?
    Par sunshine33 dans le forum MFC
    Réponses: 5
    Dernier message: 14/01/2004, 15h57
  4. rand
    Par drKzs dans le forum C
    Réponses: 6
    Dernier message: 21/09/2003, 16h39
  5. Réponses: 4
    Dernier message: 27/08/2003, 21h34

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo