Précédent   Forum du club des développeurs et IT Pro > C et C++ > C++ > Threads & Processus
Threads & Processus Forum d'entraide sur le multithreading et la programmation parallèle en 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 16/02/2013, 23h05   #1
xc78370
Nouveau Membre du Club
 
Inscription : juillet 2004
Messages : 112
Détails du profil
Informations forums :
Inscription : juillet 2004
Messages : 112
Points : 28
Points : 28
Par défaut Ecrasement de variable

Bonsoir,

Dans une boucle, je crée plusieurs Threads pointant sur une même fonction. Or une des variable de cette fonction est écrasée lors du 2eme appel de cette fonction. Je me retrouve avec 2 fois le même résultat au lieu de 2 différents.

J'ai mis en place une section critique comme je l'ai lu à plusieurs endroits, mais rien n'y fait.

Y aurait-il quelque chose que je n'aurais pas compris ?

Voila mon code :
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
 
long C_TrtExec::Executer(void)
{
long i;
struct S_ThreadParam sO_ThreadParam;
HANDLE lO_ThreadId;
 
 
	for (i=0 ; i<cI_NbTrt ; i++) {
 
		sO_ThreadParam.sO_TrtExec = this;
		sO_ThreadParam.sO_Trt = cO_ListeTrt[i]; // *** Info envoyée au thread qui est différente ici à chaque appel mais qui ne l'est plus dans le thread
 
		lO_ThreadId = CreateThread(NULL, 0, ThreadLauncher, &sO_ThreadParam, 0, NULL);
 
		AddThread(lO_ThreadId)// Ajoute simplement le ThreadId dans une liste pour le WaitForMultipleObjects
 
	}
 
	WaitForMultipleObjects( cI_NbThread, cO_ListeThread, TRUE, INFINITE);
 
	DelAllThread();
 
	return 0;
}
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 
 
DWORD WINAPI ThreadLauncher(void *pO_ThreadParam)
{
	EnterCriticalSection(&cO_CriticalSection); // cO_CriticalSection déclaré global
 
	struct S_ThreadParam *lO_ThreadParam = reinterpret_cast<struct S_ThreadParam *>(pO_ThreadParam);
	C_TrtExec *lO_TrtExec = lO_ThreadParam->sO_TrtExec;                          
	lO_TrtExec->TrtThread(lO_ThreadParam->sO_Trt); // Au deuxième appel, sO_Trt vaut la meme chose qu'au premier appel
 
	LeaveCriticalSection(&cO_CriticalSection);
 
	return 0;   
 
}
Merci de voter aide...
xc78370 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 16/02/2013, 23h16   #2
Ehonn
Membre éprouvé
 
Étudiant
Inscription : février 2012
Messages : 206
Détails du profil
Informations professionnelles :
Activité : Étudiant

Informations forums :
Inscription : février 2012
Messages : 206
Points : 438
Points : 438
Le code est étonnamment compliqué pour ce qu'il est censé faire (?)
En C++11, il existe std::thread. http://en.cppreference.com/w/cpp/thread/thread
En C++ sinon, il y a boost::thread.
OpenMP peut être aussi intéressant.

As-tu fait un affichage avant la modification par les threads de lO_ThreadParam->sO_Trt (pour vérifier que la valeur est bien modifiée) ?
As-tu fait un affichage juste après être entré et juste avant de sortir de la section critique (en augmentant la durée du calcul à l'intérieur avec un sleep(10)) pour être sûr qu'elle soit respectée ?
Ehonn est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 17/02/2013, 14h26   #3
xc78370
Nouveau Membre du Club
 
Inscription : juillet 2004
Messages : 112
Détails du profil
Informations forums :
Inscription : juillet 2004
Messages : 112
Points : 28
Points : 28
Citation:
Envoyé par Ehonn Voir le message
Le code est étonnamment pour ce qu'il est censé faire (?)
Qu'entends-tu par étonnamment long ?
Citation:
Envoyé par Ehonn Voir le message
En C++11, il existe std::thread. http://en.cppreference.com/w/cpp/thread/thread
En C++ sinon, il y a boost::thread.
OpenMP peut être aussi intéressant.
Ok, je vais jeter un coup d'oeil à ca !!!
Citation:
Envoyé par Ehonn Voir le message
As-tu fait un affichage avant la modification par les threads de lO_ThreadParam->sO_Trt (pour vérifier que la valeur est bien modifiée) ?
Oui, j'ai une log (j'ai enlevé les appels dans ce post), j'ai affiché l'objet avant de le passer au Thread ainsi que dans la fonction lO_TrtExec->TrtThread
Citation:
Envoyé par Ehonn Voir le message
As-tu fait un affichage juste après être entré et juste avant de sortir de la section critique (en augmentant la durée du calcul à l'intérieur avec un sleep(10)) pour être sûr qu'elle soit respectée ?
Non... je m'y mets...
xc78370 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 17/02/2013, 14h47   #4
Iradrille
Membre éprouvé
 
Homme
Étudiant
Inscription : juin 2012
Messages : 263
Détails du profil
Informations personnelles :
Sexe : Homme
Localisation : France

Informations professionnelles :
Activité : Étudiant

Informations forums :
Inscription : juin 2012
Messages : 263
Points : 443
Points : 443
Citation:
Envoyé par xc78370 Voir le message
Qu'entends-tu par étonnamment long ?
C'est pas vraiment la longueur le soucis, c'est plutôt le fait de faire un code non portable alors que le C++ fourni tout ce qu'il faut pour faire ça simplement, de manière portable (std::thread depuis C++11, boost::thread avant)

Sinon pour ton problème, tu n'envoi que l'adresse de la structure qui contient tes params à tes threads.

Tu n'as donc q'un seul objet ThreadParam existant, et tous les threads ont forcément les mêmes paramètres.
Iradrille est déconnecté   Envoyer un message privé Réponse avec citation 01
Vieux 17/02/2013, 15h00   #5
Ehonn
Membre éprouvé
 
Étudiant
Inscription : février 2012
Messages : 206
Détails du profil
Informations professionnelles :
Activité : Étudiant

Informations forums :
Inscription : février 2012
Messages : 206
Points : 438
Points : 438
Citation:
Envoyé par Ehonn Voir le message
Le code est étonnamment pour ce qu'il est censé faire (?)
étonnamment compliqué* (j'ai oublié un mot).
Ehonn est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 17/02/2013, 15h04   #6
xc78370
Nouveau Membre du Club
 
Inscription : juillet 2004
Messages : 112
Détails du profil
Informations forums :
Inscription : juillet 2004
Messages : 112
Points : 28
Points : 28
Citation:
Envoyé par Iradrille Voir le message
C'est pas vraiment la longueur le soucis, c'est plutôt le fait de faire un code non portable alors que le C++ fourni tout ce qu'il faut pour faire ça simplement, de manière portable (std::thread depuis C++11, boost::thread avant)
OK, j'avoue que je ne fais pas trop gaffe à ça, développant tout le temps pour la meme plateforme... Je vais y faire attention.
Citation:
Envoyé par Iradrille Voir le message
Sinon pour ton problème, tu n'envoi que l'adresse de la structure qui contient tes params à tes threads.

Tu n'as donc q'un seul objet ThreadParam existant, et tous les threads ont forcément les mêmes paramètres.
On ne peut pas envoyer autre chose qu'un pointeur à Createthread...
xc78370 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 17/02/2013, 15h09   #7
xc78370
Nouveau Membre du Club
 
Inscription : juillet 2004
Messages : 112
Détails du profil
Informations forums :
Inscription : juillet 2004
Messages : 112
Points : 28
Points : 28
Citation:
Envoyé par Ehonn Voir le message
étonnamment compliqué* (j'ai oublié un mot).
??? C'est à dire ?
xc78370 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 17/02/2013, 15h11   #8
Iradrille
Membre éprouvé
 
Homme
Étudiant
Inscription : juin 2012
Messages : 263
Détails du profil
Informations personnelles :
Sexe : Homme
Localisation : France

Informations professionnelles :
Activité : Étudiant

Informations forums :
Inscription : juin 2012
Messages : 263
Points : 443
Points : 443
Citation:
Envoyé par xc78370 Voir le message
On ne peut pas envoyer autre chose qu'un pointeur à Createthread...
Utilise un tableau (si cI_NbTrt est une constante de compilation), un vector sinon.

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
long C_TrtExec::Executer(void)
{
	long i;
	struct S_ThreadParam sO_ThreadParam[cI_NbTrt];
	HANDLE lO_ThreadId;
 
 
	for (i=0 ; i<cI_NbTrt ; i++) {		
		sO_ThreadParam[i].sO_TrtExec = this;
		sO_ThreadParam[i].sO_Trt = cO_ListeTrt[i]; // *** Info envoyée au thread qui est différente ici à chaque appel mais qui ne l'est plus dans le thread
 
		lO_ThreadId = CreateThread(NULL, 0, ThreadLauncher, &sO_ThreadParam[i], 0, NULL);
 
		AddThread(lO_ThreadId)// Ajoute simplement le ThreadId dans une liste pour le WaitForMultipleObjects
 
	}
 
	WaitForMultipleObjects( cI_NbThread, cO_ListeThread, TRUE, INFINITE);
 
	DelAllThread();
 
	return 0;
}
Iradrille est déconnecté   Envoyer un message privé Réponse avec citation 10
Vieux 17/02/2013, 15h18   #9
Arzar
Membre Expert
 
Inscription : mai 2008
Messages : 937
Détails du profil
Informations forums :
Inscription : mai 2008
Messages : 937
Points : 1 783
Points : 1 783
Vu qu'un thread met un peu de temps avant de se lancer il est très probable que la boucle for soit déjà terminée lorsque les ci_Nbtr threads démarrent pour de bon en appelant la fonction ThreadLauncher, et comme ils prennent tous en paramètre un pointeur vers la même structure sO_ThreadParam, ils partagent tous le même champ sO_Trt.

Il faut remplacer cette structure par un tableau et donner au ième thread l'adresse de la ième structure
Code :
S_ThreadParam sO_ThreadParam[NbTrt ];
Autre chose, je ne sais pas trop quel est le but recherché avec tous ces threads mais dans le code montré ils ne servent à rien du tout. Comme la fonction ThreadLauncher est protégé par un mutex, tous les thread vont attendre un par un que le mutex se libère et la fonction TrtThread () va être appelé à tour de rôle, exactement comme si on avait écrit :
Code :
1
2
3
4
for (i=0 ; i< cI_NbTrt ; i++) 
{
    TrtThread(cO_ListeTrt[i]);
}
Arzar est déconnecté   Envoyer un message privé Réponse avec citation 10
Vieux 17/02/2013, 15h25   #10
xc78370
Nouveau Membre du Club
 
Inscription : juillet 2004
Messages : 112
Détails du profil
Informations forums :
Inscription : juillet 2004
Messages : 112
Points : 28
Points : 28
Citation:
Envoyé par Arzar Voir le message
Vu qu'un thread met un peu de temps avant de se lancer il est très probable que la boucle for soit déjà terminée lorsque les ci_Nbtr threads démarrent pour de bon en appelant la fonction ThreadLauncher, et comme ils prennent tous en paramètre un pointeur vers la même structure sO_ThreadParam, ils partagent tous le même champ sO_Trt.

Il faut remplacer cette structure par un tableau et donner au ième thread l'adresse de la ième structure
Code :
S_ThreadParam sO_ThreadParam[NbTrt ];
Autre chose, je ne sais pas trop quel est le but recherché avec tous ces threads mais dans le code montré ils ne servent à rien du tout. Comme la fonction ThreadLauncher est protégé par un mutex, tous les thread vont attendre un par un que le mutex se libère et la fonction TrtThread () va être appelé à tour de rôle, exactement comme si on avait écrit :
Code :
1
2
3
4
for (i=0 ; i< cI_NbTrt ; i++) 
{
    TrtThread(cO_ListeTrt[i]);
}
Merci beaucoup. J'ai effectivement suivi le conseil d'Iradrille (qui est le même que le tient Arzar) et cela fonctionne ...
Au final la section critique n'apportait rien, je l'ai donc enlevée.
Concernant la portabilité de mon code, je vais m'attacher à faire attention.

Merci à tous.
xc78370 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 17/02/2013, 15h31   #11
Iradrille
Membre éprouvé
 
Homme
Étudiant
Inscription : juin 2012
Messages : 263
Détails du profil
Informations personnelles :
Sexe : Homme
Localisation : France

Informations professionnelles :
Activité : Étudiant

Informations forums :
Inscription : juin 2012
Messages : 263
Points : 443
Points : 443
Citation:
Envoyé par xc78370 Voir le message
Au final la section critique n'apportait rien, je l'ai donc enlevée.
Concernant la portabilité de mon code, je vais m'attacher à faire attention.
A titre d'exemple, le même code en utilisant des std::thread (pas testé pas de compilo suportant C++11 sous la main )
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
long C_TrtExec::Executer() {
	std::vector<std::thread> threads;
 
	for (long i=0; i<cI_NbTrt; ++i) {	
		S_ThreadParam sO_ThreadParam;	
		sO_ThreadParam.sO_TrtExec = this;
		sO_ThreadParam.sO_Trt = cO_ListeTrt[i];
 
		// passage du paramètre par copie
		threads.push_back(std::thread(ThreadLauncher, sO_ThreadParam));
	}
 
	for(auto t: threads) {
		t.join();
	}
 
	return 0;
}
 
void ThreadLauncher(pO_ThreadParam) {
	pO_ThreadParam.sO_TrtExec(pO_ThreadParam.sO_Trt);
}
Iradrille est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 17/02/2013, 15h38   #12
xc78370
Nouveau Membre du Club
 
Inscription : juillet 2004
Messages : 112
Détails du profil
Informations forums :
Inscription : juillet 2004
Messages : 112
Points : 28
Points : 28
Citation:
Envoyé par Iradrille Voir le message
A titre d'exemple, le même code en utilisant des std::thread (pas testé pas de compilo suportant C++11 sous la main )
Merci pour le code, mais je suis comme toi, je travaille en VCPP6 ()
xc78370 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 17/02/2013, 15h38   #13
Ehonn
Membre éprouvé
 
Étudiant
Inscription : février 2012
Messages : 206
Détails du profil
Informations professionnelles :
Activité : Étudiant

Informations forums :
Inscription : février 2012
Messages : 206
Points : 438
Points : 438
Voici une utilisation de std::thread et std::mutex
Avec une fonction et une lamda_function (juste pour l'exemple)
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
// g++ -Wall -Wextra -std=c++11 -pedantic thread_mutex.cpp -o thread_mutex && ./thread_mutex
 
#include <iostream>
#include <chrono>
#include <thread>
#include <mutex>
 
 
// Fonction pour le thread
void fct(int & v, std::mutex & m)
{
	std::cout << "Avant mutex\n";
	m.lock();
 
	std::cout << "Début mutex\n";
 
	// On dort 10 secondes
	std::this_thread::sleep_for(std::chrono::seconds(10));
 
	// On incrémente la valeur
	++v;
 
	std::cout << "Fin mutex\n";
	m.unlock();
}
 
 
int main()
{
	// On peut aussi utiliser une lambda fonction
	auto lambda_fct = [](int & v, std::mutex & m) -> void
	{
		std::cout << "Avant mutex\n";
		m.lock();
 
		std::cout << "Début mutex\n";
 
		// On dort 10 secondes
		std::this_thread::sleep_for(std::chrono::seconds(10));
 
		// On incrémente la valeur
		++v;
 
		std::cout << "Fin mutex\n";
		m.unlock();
	};
 
	int v = 0;
	std::mutex m;
 
	std::thread t0(lambda_fct, std::ref(v), std::ref(m));
	std::thread t1(fct,        std::ref(v), std::ref(m));
 
	t0.join();
	t1.join();
 
	std::cout << "Valeur finale de v = " << v << std::endl;
 
	return 0;
}
Ehonn est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 17/02/2013, 15h44   #14
xc78370
Nouveau Membre du Club
 
Inscription : juillet 2004
Messages : 112
Détails du profil
Informations forums :
Inscription : juillet 2004
Messages : 112
Points : 28
Points : 28
Ok merci pour le code.

Je garde ca sous le coude pour des jours meilleurs !!!!
xc78370 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 00h10.


 
 
 
 
Partenaires

Hébergement Web