Précédent   Forum du club des développeurs et IT Pro > C et C++ > C > Débuter
Débuter Forum d'entraide pour débuter en langage C. Avant de poster -> FAQ C
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse
 
Outils de la discussion
Publicité
'
Vieux 21/11/2012, 17h53   #1
Vrashnak
Membre à l'essai
 
Homme Tristan
Étudiant
Inscription : octobre 2012
Messages : 19
Détails du profil
Informations personnelles :
Nom : Homme Tristan
Âge : 21
Localisation : France, Somme (Picardie)

Informations professionnelles :
Activité : Étudiant

Informations forums :
Inscription : octobre 2012
Messages : 19
Points : 21
Points : 21
Par défaut Erreur segmentation en multithreads

Bonjour à tous,

Décidément, j'ai de gros problèmes d'allocation mémoire.
Je dois simuler un magasin et pour celà, je simule le comportement de chaque client par un thread et le comportement des caisses par trois threads (un par opération).
Le Client remplit un tableau de taille fixe avec des nombres aléatoires, puis choisit parmi les quatre caisses celle dont la file d'attente est la moins remplie. L'accès au tableau comprenant les valeurs des files d'attente est réglé par un sémaphore. De plus, chaque caisse ne peut avoir que N/4 clients qui y attendent (N étant le nombre total de clients). En me basant sur mes précédentes aventures, j'obtiens ceci : (très long...)

Code :
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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <pthread.h>
#include <semaphore.h>
#define MAXP 50
#define MAXC 150
#define NBCLI 100
#define PRIXMAX 99
int caisse[4];//nombre de clients attendant à chaque caisse
sem_t sem_portique, sem_acces_caisse, sem_caisse[4];//sémaphores utilisés dans la programmation
float histo[MAXC][3];
struct Cli
{
int id;
int chariot[MAXP];
};
 
typedef struct Cli Client;
/*Ls trois fonctions suivantes permettent de simuler le comportement de la caissière
Les fonctions sont adaptées à l'utilisation par un thread de type pthread_t*/
void* Moyenne (void* pdata)
{
	double* somme=malloc(sizeof(double));
	*somme=0;
	int* moyenne=(int*)pdata;
	for (int i=0; i<MAXP; i++)
	{
		*somme+=(double)*(moyenne+i);
	}
	*somme/=MAXP;
	return (void*) somme;
}
 
void* Quadratique(void* pdata)
{
	double* somme=malloc(sizeof(double));
	*somme=0;
	int* moyenne=(int*)pdata;
	for (int i=0; i<MAXP; i++)
	{
		*somme+=(double)((*(moyenne+i))*(*(moyenne+i)));
	}
	*somme/=MAXP;
	*somme=sqrt(*somme);
	return (void*) somme;
}
 
void* Cube(void* pdata)
{
	double* somme=malloc(sizeof(double));
	*somme=0;
	int* moyenne=(int*)pdata;
	for (int i=0; i<MAXP; i++)
	{
		*somme+=(double)((*(moyenne+i))*(*(moyenne+i))*(*(moyenne+i)));
	}
	return (void*) somme;
}
/*La procédure client utilisant les sémaphores. La fonction est utilisée par un thread.*/
void* Client_sim(void* pdata)
{
	int i, idc=(int) pdata;
	Client C;
	C.id=idc;
	sem_wait(&sem_portique);//Entrée du client dans le magasin si possible
	printf("Entree du client %d \n",C.id);
	for(i=0;i<MAXP;i++)
	{
		C.chariot[i]=(int)(1+rand())%(50);//remplissage du chariot du client
	}
	printf("Fin des achats pour le client %d \n",C.id);
	sem_wait(&sem_acces_caisse);//Demande du client pour un accès au tableau des files des caisses
	i=find_caisse_minimale();//Recherche et sauvegarde de la caisse la moins remplie
	sem_post(&sem_acces_caisse);
	sem_wait(&sem_caisse[i]);//attente à la caisse ayant la plus petite file d'attente
	caisse_client(C.chariot, i);
	sem_post(&sem_caisse[i]);
	printf("Temps passe dans le magasin pour le client %d : temps \n",C.id);
	sem_post(&sem_portique);//Sortie du client
	free(C.chariot[]);
}
//Cette fonction est la seule utilisant un if. Elle retourne le numéro de la caisse ayant le plus petit nombre de 
//clients qui y attendent. Si deux caisses ont le même nombre de clients y attendant, c'est la première qui est renvoyée.
int find_caisse_minimale()
{
	int i,min=0;
	for(i=1;i<4;i++)
	{
		if(caisse[min]<caisse[i])
		{
			min=caisse[i];
		}
	}
	caisse[min]--;
	return min;
}
//Cette procédure calcule le ticket d'un client et décrémente le sémaphore associé une fois le travail effectué.
//Elle utilise la même structure que la caisse threadée du deuxième programme séquentiel.
void caisse_client(int chariot[], int i)
{
	pthread_t moy, qua, cub;
	void* un;
	void* deux;
	void* trois;
	double* val;
	pthread_create(&moy,NULL,Moyenne,chariot);
	pthread_create(&qua,NULL,Quadratique,chariot);
	pthread_create(&cub,NULL,Cube,chariot);
	pthread_join(moy,&un);
	pthread_join(qua,&deux);
	pthread_join(cub,&trois);
	val=(double*)un;
	histo[i][0]=(double)*val;
	val=(double*)deux;
	histo[i][1]=(double)*val;
	val=(double*)trois;
	histo[i][2]=(double)*val;
	free(un);
	free(deux);
	free(trois);
	sem_wait(&sem_acces_caisse);
	caisse[i]++;
	sem_post(&sem_acces_caisse);	
}
int main()
{
	int i;
	void* useless;
	caisse[0]=MAXC/4;caisse[1]=MAXC/4;caisse[2]=MAXC/4;caisse[3]=MAXC/4;
	pthread_t clients[MAXC];
	srand(time(NULL));
	sem_init(&sem_portique,0,NBCLI);
	sem_init(&sem_acces_caisse,0,1);
	for(i=0;i<4;i++)
	{
		sem_init(&sem_caisse[i],0,caisse[i]);
	}
	for(i=0;i<MAXC;i++)
	{
		pthread_create(&clients[i],NULL,Client_sim,i);
	}
	for(i=0;i<MAXC;i++)
	{
		pthread_join(useless,&clients[i]);
		free(useless);
	}
	for(i=0;i<MAXC;i++)
	{
		printf("Ticket du client %d : %0.4f %0.4f %0.4f \n",i,histo[i][0],histo[i][1],histo[i][2]);
	}
	return 0;
}
La compilation fonctionne bien, mais lors de l'exécution parallèle des clients, une Erreur de segmentation intervient au bout d'un moment (avant la création du dernier client).

Exemple d'exécution (la fin de celle-ci) :
Code :
1
2
3
4
5
6
7
8
9
10
Fin des achats pour le client 113 
Temps passe dans le magasin pour le client 76 : temps 
Temps passe dans le magasin pour le client 73 : temps 
Temps passe dans le magasin pour le client 96 : temps 
Entree du client 114 
Fin des achats pour le client 114 
Temps passe dans le magasin pour le client 105 : temps 
Temps passe dans le magasin pour le client 102 : temps 
Temps passe dans le magasin pour le client 88 : temps 
Erreur de segmentation (core dumped)
(je dois implémenter un chronomètre, mais je le ferai lorsque le programme s'exécutera comme il faut, d'où l'affichage un peu inutile...)

Je travaille dessus depuis vendredi et commence sérieusement à en avoir marre (je suis désolé de mon manque de persévérance). Je me doute que le problème doit venir de ma fonction Client_sim, où je dois probablement mal utiliser un pointeur, mais même en reprenant tous mes pointeurs un par un, rien à faire. Je n'arrive pas à utiliser Valgrind qui pourtant pourrait probablement me sauver la vie, et j'avoue que je n'en peux plus.

Si quelqu'un peut m'aider, je lui devrai une reconnaissance éternelle.

Ci-joint le code du programme.

Cordialement,

Vrashnak
Fichiers attachés
Type de fichier : c thr_full.c (3,9 Ko, 2 affichages)
Vrashnak est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 22/11/2012, 09h35   #2
transgohan
Expert Confirmé
 
Avatar de transgohan
 
Homme Baptiste ROUSSEL
Développeur Temps réel Embarqué
Inscription : janvier 2011
Messages : 1 316
Détails du profil
Informations personnelles :
Nom : Homme Baptiste ROUSSEL
Localisation : France, Territoire de Belfort (Franche Comté)

Informations professionnelles :
Activité : Développeur Temps réel Embarqué

Informations forums :
Inscription : janvier 2011
Messages : 1 316
Points : 2 953
Points : 2 953
Tu fais un free sur une variable non allouée dynamiquement c'est viable ça ? Cela me paraît pas très propre. :/
Sinon je n'ai rien vu de suspect dans ton programme, as-tu tenté de le lancer avec gdb ou autre debugguer ?
__________________
Toujours se souvenir que la majorité des ennuis viennent de l'espace occupé entre la chaise et l'écran de l'ordinateur.
transgohan est déconnecté   Envoyer un message privé Réponse avec citation 10
Vieux 22/11/2012, 10h15   #3
DrDarko
Membre habitué
 
Homme Allan
Étudiant
Inscription : août 2012
Messages : 82
Détails du profil
Informations personnelles :
Nom : Homme Allan
Âge : 23
Localisation : France, Yvelines (Île de France)

Informations professionnelles :
Activité : Étudiant

Informations forums :
Inscription : août 2012
Messages : 82
Points : 146
Points : 146
Pour regarder les problèmes que tu as avec la mémoire valgrind c'est pas mal. Ça te permettra de voir si tu libères bien tout ce que tu as alloué.
DrDarko est déconnecté   Envoyer un message privé Réponse avec citation 10
Vieux 22/11/2012, 16h08   #4
Vrashnak
Membre à l'essai
 
Homme Tristan
Étudiant
Inscription : octobre 2012
Messages : 19
Détails du profil
Informations personnelles :
Nom : Homme Tristan
Âge : 21
Localisation : France, Somme (Picardie)

Informations professionnelles :
Activité : Étudiant

Informations forums :
Inscription : octobre 2012
Messages : 19
Points : 21
Points : 21
Bonjour,

merci à vous de m'aider.
J'ai retiré le free(C.chariot[]) comme tu me le proposes transgohan, mais ça n'a rien changé.
J'ai aussi retiré le free(useless) dans mon main(), sans plus de résultats.

Code :
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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <pthread.h>
#include <semaphore.h>
#define MAXP 50
#define MAXC 150
#define NBCLI 100
#define PRIXMAX 99
int caisse[4];//nombre de clients attendant à chaque caisse
sem_t sem_portique, sem_acces_caisse, sem_caisse[4];//sémaphores utilisés dans la programmation
float histo[MAXC][3];
struct Cli
{
int id;
int chariot[MAXP];
};
 
typedef struct Cli Client;
/*Ls trois fonctions suivantes permettent de simuler le comportement de la caissière
Les fonctions sont adaptées à l'utilisation par un thread de type pthread_t*/
void* Moyenne (void* pdata)
{
	double* somme=malloc(sizeof(double));
	*somme=0;
	int* moyenne=(int*)pdata;
	for (int i=0; i<MAXP; i++)
	{
		*somme+=(double)*(moyenne+i);
	}
	*somme/=MAXP;
	return (void*) somme;
}
 
void* Quadratique(void* pdata)
{
	double* somme=malloc(sizeof(double));
	*somme=0;
	int* moyenne=(int*)pdata;
	for (int i=0; i<MAXP; i++)
	{
		*somme+=(double)((*(moyenne+i))*(*(moyenne+i)));
	}
	*somme/=MAXP;
	*somme=sqrt(*somme);
	return (void*) somme;
}
 
void* Cube(void* pdata)
{
	double* somme=malloc(sizeof(double));
	*somme=0;
	int* moyenne=(int*)pdata;
	for (int i=0; i<MAXP; i++)
	{
		*somme+=(double)((*(moyenne+i))*(*(moyenne+i))*(*(moyenne+i)));
	}
	return (void*) somme;
}
/*La procédure client utilisant les sémaphores. La fonction est utilisée par un thread.*/
void* Client_sim(void* pdata)
{
	int i, idc=(int) pdata;
	Client C;
	C.id=idc;
	sem_wait(&sem_portique);//Entrée du client dans le magasin si possible
	printf("Entree du client %d \n",C.id);
	for(i=0;i<MAXP;i++)
	{
		C.chariot[i]=(int)(1+rand())%(50);//remplissage du chariot du client
	}
	printf("Fin des achats pour le client %d \n",C.id);
	sem_wait(&sem_acces_caisse);//Demande du client pour un accès au tableau des files des caisses
	i=find_caisse_minimale();//Recherche et sauvegarde de la caisse la moins remplie
	sem_post(&sem_acces_caisse);
	sem_wait(&sem_caisse[i]);//attente à la caisse ayant la plus petite file d'attente
	caisse_client(C.chariot, i, C.id);
	sem_post(&sem_caisse[i]);
	printf("Temps passe dans le magasin pour le client %d : temps \n",C.id);
	sem_post(&sem_portique);//Sortie du client
}
//Cette fonction est la seule utilisant un if. Elle retourne le numéro de la caisse ayant le plus petit nombre de 
//clients qui y attendent. Si deux caisses ont le même nombre de clients y attendant, c'est la première qui est renvoyée.
int find_caisse_minimale()
{
	int i,min=0;
	for(i=1;i<4;i++)
	{
		if(caisse[min]<caisse[i])
		{
			min=caisse[i];
		}
	}
	caisse[min]--;
	return min;
}
//Cette procédure calcule le ticket d'un client et décrémente le sémaphore associé une fois le travail effectué.
//Elle utilise la même structure que la caisse threadée du deuxième programme séquentiel.
void caisse_client(int chariot[], int i, int id)
{
	pthread_t moy, qua, cub;
	void* un;
	void* deux;
	void* trois;
	double* val;
	pthread_create(&moy,NULL,Moyenne,chariot);
	pthread_create(&qua,NULL,Quadratique,chariot);
	pthread_create(&cub,NULL,Cube,chariot);
	pthread_join(moy,&un);
	pthread_join(qua,&deux);
	pthread_join(cub,&trois);
	val=(double*)un;
	histo[id][0]=(double)*val;
	val=(double*)deux;
	histo[id][1]=(double)*val;
	val=(double*)trois;
	histo[id][2]=(double)*val;
	free(un);
	free(deux);
	free(trois);
	sem_wait(&sem_acces_caisse);
	caisse[i]++;
	sem_post(&sem_acces_caisse);	
}
int main()
{
	int i;
	void* useless;
	caisse[0]=MAXC/4;caisse[1]=MAXC/4;caisse[2]=MAXC/4;caisse[3]=MAXC/4;
	pthread_t clients[MAXC];
	srand(time(NULL));
	sem_init(&sem_portique,0,NBCLI);
	sem_init(&sem_acces_caisse,0,1);
	for(i=0;i<4;i++)
	{
		sem_init(&sem_caisse[i],0,caisse[i]);
	}
	for(i=0;i<MAXC;i++)
	{
		pthread_create(&clients[i],NULL,Client_sim,i);
	}
	for(i=0;i<MAXC;i++)
	{
		pthread_join(useless,&clients[i]);
	}
	for(i=0;i<MAXC;i++)
	{
		printf("Ticket du client %d : %0.4f %0.4f %0.4f \n",i,histo[i][0],histo[i][1],histo[i][2]);
	}
	return 0;
}
Et lorsque je passe le programme obtenu à la moulinette de valgrind, j'obtiens ces messages d'erreurs :

Code :
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
Entree du client 118 
Fin des achats pour le client 118 
==7606== Use of uninitialised value of size 4
==7606==    at 0x41F46D4E: pthread_join (in /lib/libpthread-2.14.90.so)
==7606==    by 0x8048C39: main (in /home/till_gray/Dropbox/projet tse/fullthr)
==7606==  Uninitialised value was created by a stack allocation
==7606==    at 0x8048AE2: main (in /home/till_gray/Dropbox/projet tse/fullthr)
==7606== 
==7606== Use of uninitialised value of size 4
==7606==    at 0x41F46D5D: pthread_join (in /lib/libpthread-2.14.90.so)
==7606==    by 0x8048C39: main (in /home/till_gray/Dropbox/projet tse/fullthr)
==7606==  Uninitialised value was created by a stack allocation
==7606==    at 0x8048AE2: main (in /home/till_gray/Dropbox/projet tse/fullthr)
==7606== 
==7606== Conditional jump or move depends on uninitialised value(s)
==7606==    at 0x41F46D68: pthread_join (in /lib/libpthread-2.14.90.so)
==7606==    by 0x8048C39: main (in /home/till_gray/Dropbox/projet tse/fullthr)
==7606==  Uninitialised value was created by a stack allocation
==7606==    at 0x8048AE2: main (in /home/till_gray/Dropbox/projet tse/fullthr)
==7606== 
==7606== Conditional jump or move depends on uninitialised value(s)
==7606==    at 0x41F46DA9: pthread_join (in /lib/libpthread-2.14.90.so)
==7606==    by 0x8048C39: main (in /home/till_gray/Dropbox/projet tse/fullthr)
==7606==  Uninitialised value was created by a stack allocation
==7606==    at 0x8048AE2: main (in /home/till_gray/Dropbox/projet tse/fullthr)
==7606== 
==7606== Conditional jump or move depends on uninitialised value(s)
==7606==    at 0x41F46DB5: pthread_join (in /lib/libpthread-2.14.90.so)
==7606==    by 0x8048C39: main (in /home/till_gray/Dropbox/projet tse/fullthr)
==7606==  Uninitialised value was created by a stack allocation
==7606==    at 0x8048AE2: main (in /home/till_gray/Dropbox/projet tse/fullthr)
==7606== 
==7606== Use of uninitialised value of size 4
==7606==    at 0x41F46DBF: pthread_join (in /lib/libpthread-2.14.90.so)
==7606==    by 0x8048C39: main (in /home/till_gray/Dropbox/projet tse/fullthr)
==7606==  Uninitialised value was created by a stack allocation
==7606==    at 0x8048AE2: main (in /home/till_gray/Dropbox/projet tse/fullthr)
==7606== 
==7606== 
==7606== Process terminating with default action of signal 11 (SIGSEGV)
==7606==  Bad permissions for mapped region at address 0x8048F1D
==7606==    at 0x41F46DBF: pthread_join (in /lib/libpthread-2.14.90.so)
==7606==    by 0x8048C39: main (in /home/till_gray/Dropbox/projet tse/fullthr)
==7606== 
==7606== HEAP SUMMARY:
==7606==     in use at exit: 20,560 bytes in 154 blocks
==7606==   total heap usage: 211 allocs, 57 frees, 21,016 bytes allocated
==7606== 
==7606== LEAK SUMMARY:
==7606==    definitely lost: 0 bytes in 0 blocks
==7606==    indirectly lost: 0 bytes in 0 blocks
==7606==      possibly lost: 20,536 bytes in 151 blocks
==7606==    still reachable: 24 bytes in 3 blocks
==7606==         suppressed: 0 bytes in 0 blocks
==7606== Rerun with --leak-check=full to see details of leaked memory
==7606== 
==7606== For counts of detected and suppressed errors, rerun with: -v
==7606== ERROR SUMMARY: 6 errors from 6 contexts (suppressed: 0 from 0)
Processus arrêté
Je suis vraiment désolé de vous embêter avec ça, mais je ne sais plus quoi faire. Le but de ce programme est de nous faire travailler la programmation multithreadée avec sémaphores, mais je travaille plus mes allocations mémoires qu'autre chose...

Que m'indique valgrind ? Pourquoi ma fonction pthread_join ligne 145 ne marche-t-elle pas alors que j'applique la même syntaxe dans mes trois fonctions de calcul et que celles-ci ne posent aucun problème ?

Merci d'avance,

Vrashnak
Vrashnak est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 22/11/2012, 16h30   #5
diogene
Responsable Modération
 
Avatar de diogene
 
Homme Patrick Gonord
Enseignant Chercheur
Inscription : juin 2005
Messages : 5 488
Détails du profil
Informations personnelles :
Nom : Homme Patrick Gonord
Localisation : France, Essonne (Île de France)

Informations professionnelles :
Activité : Enseignant Chercheur
Secteur : Enseignement

Informations forums :
Inscription : juin 2005
Messages : 5 488
Points : 13 125
Points : 13 125
Citation:
Que m'indique valgrind ? Pourquoi ma fonction pthread_join ligne 145 ne marche-t-elle pas alors que j'applique la même syntaxe dans mes trois fonctions de calcul et que celles-ci ne posent aucun problème
Ce n'est pas un problème de syntaxe. Et tu ne fais pas la même chose sur la ligne 145 : les deux arguments de la fonction sont permutés.
__________________
Publication : Concepts en C

Mon avatar : Glenn Gould

--------------------------------------------------------------------------
Une réponse vous a été utile ? Remerciez son auteur en cliquant le pouce vert !
diogene est déconnecté   Envoyer un message privé Réponse avec citation 10
Vieux 22/11/2012, 16h50   #6
Vrashnak
Membre à l'essai
 
Homme Tristan
Étudiant
Inscription : octobre 2012
Messages : 19
Détails du profil
Informations personnelles :
Nom : Homme Tristan
Âge : 21
Localisation : France, Somme (Picardie)

Informations professionnelles :
Activité : Étudiant

Informations forums :
Inscription : octobre 2012
Messages : 19
Points : 21
Points : 21
Merci à vous Diogène.

Effectivement, en n'inversant plus le thread et la variable qui est censée récupérer la "valeur" (bien qu'il ne renvoie rien), ça fonctionne tout de suite mieux.

Encore merci à vous. Hop, problème résolu.
Vrashnak est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse Cette discussion est résolue.
Outils de la discussion

Navigation rapide


Fuseau horaire GMT +2. Il est actuellement 06h19.


 
 
 
 
Partenaires

Hébergement Web