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

Linux Discussion :

Segmentation fault, trop de thread fils


Sujet :

Linux

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    126
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 126
    Par défaut Segmentation fault, trop de thread fils
    Bonjour, je suis sur un projet pour les cours. On doit réaliser un système de lecteurs écrivains :

    Des requêtes (lecture ou écriture) arrivent, et elles doivent être insérées dans une file d'attente avant d'être traitées par le lancement d'un thread lecteur ou écrivain.

    Dans ma modélisation, je lance deux threads générateurs de requêtes (le premier génère des demandes de lectures, l'autre... des écritures). Les générateurs communiquent avec main() via un tableau que j'ai appelé BOITE (les générateurs remplissent la boite, le main la vide dans la file d'attente). La file d'attente est une liste chaînée.

    Bon, j'en ai fini pour le pitch, voici mon code.

    L'heure du crime

    Comme vous pouvez le voir, j'ai mis NB_QUERIES à 500, et parfois j'obtiens une segmentation fault :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    	E118 ecrit
    	L119 lit
    	L120 lit
    	E121 ecrit
    	E122 ecrit
    	E123 ecrit
    	E125 ecrit
    Segmentation fault
    Et voici ce que dit gdb :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    	L204 lit
    	L205 lit
    	E206 ecrit
    	E207 ecrit
    	L209 lit
     
    Program received signal EXC_BAD_ACCESS, Could not access memory.
    Reason: KERN_INVALID_ADDRESS at address: 0xb6b25070
    [Switching to process 478 thread 0xee03]
    0x90e35548 in pthread_getspecific ()
    Bref, je me doute que le problème est dû au nombre très important de threads, mais je ne vois pas trop comment le résoudre.

    Merci de votre aide.

  2. #2
    Membre Expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2008
    Messages
    1 515
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Octobre 2008
    Messages : 1 515
    Par défaut
    Citation Envoyé par Galdon Voir le message
    Bref, je me doute que le problème est dû au nombre très important de threads
    Non, il est dû à un bug dans ton code.

  3. #3
    Membre confirmé
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    126
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 126
    Par défaut
    Dans ce cas, comment expliquer que ce bug n'intervient jamais pour un nombre de requêtes inférieur à 100 ?

    Et avec 500 requêtes, le bug ne se produit pas forcément à chaque exécution, parfois le programme termine sans problème.

  4. #4
    Membre Expert Avatar de nicolas.sitbon
    Profil pro
    Inscrit en
    Août 2007
    Messages
    2 015
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France

    Informations forums :
    Inscription : Août 2007
    Messages : 2 015
    Par défaut
    Il y a des comportements indéterminés dans ton programme, notamment dans le dernier argument de pthread_create().

  5. #5
    Membre confirmé
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    126
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 126
    Par défaut
    Qu'est ce qu'un comportement indéterminé et en quoi est-ce que le passage de i en paramètre est il indéterminé ?

    (avec pthread_create, le dernier argument est obligatoirement de type void).

  6. #6
    Membre éclairé

    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Février 2005
    Messages
    464
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : Industrie

    Informations forums :
    Inscription : Février 2005
    Messages : 464
    Par défaut
    Bonjour,
    J'ai compilé et exécuté ton code et le bog s'est produit.
    A vrai dire je n'ai pas compris tous les détails, comme l'application est à caractère 'abstrait'.
    Une chose cependant m'a frappée : il est inutile de poser des verrous sur des affectations de mots processeurs, ces opérations sont atomiques, par contre tu dois le faire sur l'ensemble des opérations modifiant des informations qui y sont liées. Je parle de la fonction générateur.
    Autre petit détail, tu débloques un verrou dans main() alors que tu ne l'a pas bloqué auparavant (je pense que le bog venait de la car l'arrêt du soft disait que tu accédais à un verrou dont tu n'est pas le propriétaire, je pense qu'a ce moment-l) un thread avait utilisé le verrou).
    Ces petites modifications faites j'ai pu exécuter plusieurs fois de suite ton programme sans accident.

    Voici ci-dessous le patch pour faire tes essais :
    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
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
     
    --- main.c.bak	2008-12-02 00:20:34.000000000 +0100
    +++ main.c	2008-12-02 01:32:04.000000000 +0100
    @@ -4,10 +4,26 @@
     #include <time.h>
     #include <sched.h>
     #include <errno.h>
    +#include <unistd.h>
    +#include <assert.h>
     
     /*
      gcc projet4.c -o p4 -lpthread -g3 -Wall
    -gdb p4
    +main.c: Dans la fonction «generateur» :
    +main.c:35: attention : transtypage d'un pointeur vers un entier de taille différente
    +main.c:53: attention : déclaration implicite de la fonction « «usleep» »
    +main.c: Dans la fonction «lecteur» :
    +main.c:82: attention : format «%d» expects type «int», but argument 2 has type «void *»
    +main.c:84: attention : control reaches end of non-void function
    +main.c: Dans la fonction «ecrivain» :
    +main.c:88: attention : format «%d» expects type «int», but argument 2 has type «void *»
    +main.c:91: attention : control reaches end of non-void function
    +main.c: Dans la fonction «ajouterFile» :
    +main.c:96: attention : déclaration implicite de la fonction « «filePleine» »
    +main.c: Dans la fonction «main» :
    +main.c:193: attention : transtypage vers un pointeur depuis un entier de taille différente
    +main.c:199: attention : transtypage vers un pointeur depuis un entier de taille différente
    +
     */
     
     //	Structure de file d'attente
    @@ -20,23 +36,26 @@
     
     //	Déclarations globales
     char priorite;
    -pthread_mutex_t mutex1;
     int BOITE[2];	//	Le tableau BOITE sert d'interface entre le(s) générateur(s) et main()
     
     //	Paramètres du générateur de requêtes
     pthread_mutex_t mutex_gen;
    -int NB_QUERIES = 500;
    +const int NB_QUERIES = 500;
     int NB_CREES = 0;
     int END = 0;
     int TAILLE_FILE = 5;
     int PERTES = 0;		//	Requêtes qui n'ont pu être traités pour cause de file d'attente pleine
     
    +int filePleine(llfile file_attente) ;
    +
     void *generateur(void *param){
     	int type = (int)param;		//	Forcage de type à l'ancienne, sinon : erreur compilation illisible
     	int crees = 0;				//	Au début, on n'a pas encore créé de requête
     	int pause = 0;
     	int ma_boite = 0;
     
    +	// j'ajoute ca car j'ai eu peur dans ton code principale : tu incremente i++ et tu le passes en argument dans cette fonction ?!
    +	assert((type < 2) && (type >=0)) ;
     	printf("generateur %d initialise\n",type);
     
     	//	Tant qu'on n'a pas atteint le nombre de requêtes à générer pour la simulation, on créé une nouvelle requête
    @@ -44,7 +63,6 @@
     
     		pthread_mutex_lock(&mutex_gen);
     		ma_boite = BOITE[type];
    -		pthread_mutex_unlock(&mutex_gen);
     
     		//	Si ma boite est vide, je vais générer une requête
     		if(ma_boite == 0){
    @@ -53,41 +71,33 @@
     			usleep(pause);
     			//printf("sortie pause : %d ms\n",pause/1000);
     
    -			pthread_mutex_lock(&mutex_gen);
     			BOITE[type] = 1;
    -			pthread_mutex_unlock(&mutex_gen);
     
     			//	Quand on a terminé une itération, on vient de générer une nouvelle requête, donc on met à jour le compteur
    -			pthread_mutex_lock(&mutex_gen);
     			NB_CREES++;
     			crees = NB_CREES;
    -			pthread_mutex_unlock(&mutex_gen);
     		}
     		//	Sinon, j'attends que le main me prévienne que la boite est vide (pour éviter de pédaler dans la semoule)
     		/*else{
     
     		}*/
    +		pthread_mutex_unlock(&mutex_gen);
     	}
    -	pthread_mutex_lock(&mutex_gen);
     	END++;
    -	pthread_mutex_unlock(&mutex_gen);
     
     	return 0;
     }
     
    -void *lecteur(void *tid){
    -	pthread_mutex_lock(&mutex1);
    -	pthread_mutex_unlock(&mutex1);
    -
    +void * lecteur(void *tid){
     	printf("\tL%d lit\n",tid);
     	usleep(10*1000);
    +	return NULL ;
     }
     
    -void *ecrivain(void *tid){
    -	pthread_mutex_lock(&mutex1);
    +void * ecrivain(void *tid){
     	printf("\tE%d ecrit\n",tid);
     	usleep(30*1000);
    -	pthread_mutex_unlock(&mutex1);
    +	return NULL ;
     }
     
     //	L'ajout d'une requête en file d'attente est une insertion en fin de liste
    @@ -176,10 +186,9 @@
     
     	llfile file_attente = NULL;	//	Création de la file d'attente
     
    -	pthread_mutex_init(&mutex1, NULL);
     	pthread_mutex_init(&mutex_gen, NULL);
     
    -	//	Création des deux générateurs de lecteurs et d'écrivains
    +	// Création des deux générateurs de lecteurs et d'écrivains
     	pthread_create(&gen_lecteurs, NULL, generateur, (void*)0);
     	pthread_create(&gen_ecrivains, NULL, generateur, (void*)1);
     
    @@ -227,7 +236,8 @@
     			BOITE[0] = 0;
     			BOITE[1] = 0;
     		}
    -		pthread_mutex_unlock(&mutex_gen);
    +		// Pkoi ceci ?
    +		// pthread_mutex_unlock(&mutex_gen);
     	}
     
     	pthread_join(gen_lecteurs,NULL);
    PS : pour l'assertion y'a pas de pb, j'avais mal lu.
    PS2: n'oublie pas de marquer resolu ton sujet quand ton pb sera réglé.

  7. #7
    Membre Expert Avatar de nicolas.sitbon
    Profil pro
    Inscrit en
    Août 2007
    Messages
    2 015
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France

    Informations forums :
    Inscription : Août 2007
    Messages : 2 015
    Par défaut
    Citation Envoyé par Galdon Voir le message
    Qu'est ce qu'un comportement indéterminé et en quoi est-ce que le passage de i en paramètre est il indéterminé ?

    (avec pthread_create, le dernier argument est obligatoirement de type void).
    Non le dernier paramètre est de type (void*), hors toi tu castes ton i (type int) en (void*) ce que tu n'as pas le droit de faire.

Discussions similaires

  1. Segmentation fault with thread
    Par Kroui dans le forum Interfaces Graphiques
    Réponses: 6
    Dernier message: 05/08/2011, 13h14
  2. Segmentation fault avec threads
    Par aljekeny dans le forum Linux
    Réponses: 3
    Dernier message: 12/01/2009, 19h37
  3. Réponses: 3
    Dernier message: 21/01/2008, 14h38
  4. Réponses: 13
    Dernier message: 13/07/2004, 15h41
  5. Comment contrer la "segmentation fault" ?
    Par guillaume_pfr dans le forum C
    Réponses: 15
    Dernier message: 08/08/2003, 13h43

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