Bienvenue, Invité. Merci de vous connecter ou de vous inscrire.
Avez-vous perdu votre e-mail d'activation ?

Auteur Sujet: Comment bien utiliser les mutex ?  (Lu 40353 fois)

0 Membres et 1 Invité sur ce sujet

Lolilolight

  • Hero Member
  • *****
  • Messages: 1232
    • Voir le profil
Comment bien utiliser les mutex ?
« le: Juillet 24, 2013, 01:05:00 pm »
Salut,

il y a un crash avec les sf::thread lorsque l'on récupère des variables dans le constructeur d'une classe qui instancie un sf::thread mais le problème ne survient qu'avec des méthodes statique qui renvoie une variable qui doit être partagée entre plusieurs thread.

SrkChannel::SrkChannel(SrkServer &server, string name) : server(server), name (name), thread (&SrkChannel::run, this)
{
    this->map = World::getMap("Map test");
    ...
}
 

Ca plante dans la fonction exécutée par mon thread, le débugueur ne me donne pas plus d'infos que ça, il me dis juste que ça plante lorsque le sf::thread exécute la fonction, lorque je veux utiliser la variable, ça plante dans la fonction entryPoint du fichier ThreadImpl.
#0 00436578 CellMap::getCenter(this=0xabababab) (D:\Projets-c++\SorrokSrv\world\mapCell.cpp:91)
#1 00434A8C GridMap::getPath(this=0x2f700e0, startPos=..., finalPos=...) (D:\Projets-c++\SorrokSrv\world\gridMap.cpp:425)
#2 00422FED SrkChannel::run(this=0x3014c28) (D:\Projets-c++\SorrokSrv\NetworkEngine\srkchannel.cpp:77)
#3 004CE8CD sf::priv::ThreadMemberFunc<SrkChannel>::run(this=0x2f7f220) (C:/SFML-2.0/include/SFML/System/Thread.inl:58)
#4 004A0297 sf::priv::ThreadImpl::entryPoint () (??:??)
#5 75861287 msvcrt!_itow_s() (C:\Windows\syswow64\msvcrt.dll:??)
#6 75861328 msvcrt!_endthreadex() (C:\Windows\syswow64\msvcrt.dll:??)
#7 749633AA KERNEL32!BaseCleanupAppcompatCacheSupport() (C:\Windows\syswow64\kernel32.dll:??)
#8 06EBFFD4 ?? () (??:??)
#9 77189EF2 ntdll!RtlpNtSetValueKey() (C:\Windows\system32\ntdll.dll:??)
#10 00DE70D0 ?? () (??:??)
#11 77189EC5 ntdll!RtlpNtSetValueKey() (C:\Windows\system32\ntdll.dll:??)
#12 758612E5 msvcrt!_endthreadex() (C:\Windows\syswow64\msvcrt.dll:??)
#13 ?? ?? () (??:??)

Y'a moyen de contourner le bug en récupérant l'objet dans une autre fonction que celle qui instancie le thread.

Bref faudrait que je poste ça dans les rapports de bugs avec un code tout bête qui reproduit le bug, peut être que certains pourront le corriger, moi, je pencherai plutôt pour une mauvaise initialisation de variables statiques partagées entre plusieurs threads.
PS : je pense que j'avais déjà eu ce bug plus tôt.
PS 2 : je voulais même passé au c++11 à cause de ça mais bon j'arrive pas à le faire marcher.
« Modifié: Août 11, 2013, 10:38:30 am par Lolilolight »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32498
    • Voir le profil
    • SFML's website
    • E-mail
Re : Bug avec les threads.
« Réponse #1 le: Juillet 24, 2013, 01:18:59 pm »
Il faut vraiment arrêter avec les conclusions hâtives. Là il y a 99.99% de chances pour que ce soit ton code qui est foireux, pas sf::Thread. Sûrement une mauvaise gestion de variables partagées entre threads.

Poste un code complet minimal qui reproduit le problème, ou, si c'est trop compliqué, au moins tous les morceaux de code qui sont pertinents.
Laurent Gomila - SFML developer

Lolilolight

  • Hero Member
  • *****
  • Messages: 1232
    • Voir le profil
Re : Bug avec les threads.
« Réponse #2 le: Juillet 24, 2013, 04:39:48 pm »
Bon avec un code complet minimal je n'ai pas ce crash..., mais ça me le faisais que en mode débug, ce qui m'empêchais de pouvoir débuguer le reste du code...
Bref surement une erreur quelque part..., ici ça va vu que j'ai réussi à contourner le problème en mettant ça dans une méthode start plutôt que dans le constructeur.

Lolilolight

  • Hero Member
  • *****
  • Messages: 1232
    • Voir le profil
Re : Bug avec les threads.
« Réponse #3 le: Juillet 25, 2013, 08:49:51 am »
Bon c'est un problème d'accès concurrant ça c'est sûr mais même en mettant des mutex ça ne semble pas fonctionner. :/

J'ai déclaré le mutex dans un fichier .h (qui contient tout ce qui est variable globale) mais je suis obligé de le déclarer en static sinon j'ai des problèmes de multiple definition of, je ne peux pas le déclarer en dehors du main sinon je n'ai pas accès au mutex dans les autres fichiers.
J'ai aussi essayé de déclarer le mutex dans le main et le passer à toutes mes classes (chose trop lourde à faire.) mais ça ne résoud pas le problème. :/

Quand je fais un mutex.lock et mutex.unlock dans mes deux fonctions appelé par mes 2 threads, j'ai toujours un problème d'accès concurrant.

Lolilolight

  • Hero Member
  • *****
  • Messages: 1232
    • Voir le profil
Re : Bug avec les threads.
« Réponse #4 le: Juillet 25, 2013, 08:59:43 am »
Bon bah au final, en faisant plusieurs tests, j'ai trouvé d'où vient le bug.

Quand j'initialise une variable statique, avec une méthode statique dans le .cpp qui initialise d'autres variables, les mutex ne marchent pas pour ces autres variables.

J'espère que j'aurai été assez clair, c'est assez difficile de faire un code minimal qui reproduit le problème car je devrai m'arrangerai pour faire des accès concurrents...
« Modifié: Juillet 25, 2013, 09:09:24 am par Lolilolight »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32498
    • Voir le profil
    • SFML's website
    • E-mail
Re : Bug avec les threads.
« Réponse #5 le: Juillet 25, 2013, 09:06:30 am »
Citer
Les mutex ne fonctionnent pas pour les variables qui sont initialisée, non pas avec un constructeur, mais avec une méthode statique.
Là comme ça, ça ne veut pas dire grand chose. Peux-tu développer ?
Laurent Gomila - SFML developer

Lolilolight

  • Hero Member
  • *****
  • Messages: 1232
    • Voir le profil
Re : Bug avec les threads.
« Réponse #6 le: Juillet 25, 2013, 09:18:48 am »
Ok alors je vais essayer de détailler ça avec un code. (Pas facile à expliquer. :/ )

J'ai une classe Bidule qui contient une méthode statique qui initialise une variable statique Truc
Voici le .h :
class Bidule {
private :
       static Truc& getTruc() {
                Truc *t = new Truc();
                return *t;
       }
       static Truc &truc;
};
 
Et le .cpp
Truc& Bidule::truc = getTruc();
 

Le mutex ne marche pas pour toutes les variables de la classe Truc.

Par contre si j'initialise les variables de la classe Truc plus tard, c'est à dire, dans une autre méthode que le constructeur de la classse truc, là, les mutex marchent.

Alors voici ma question : est ce normal ?
« Modifié: Juillet 25, 2013, 09:25:01 am par Lolilolight »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32498
    • Voir le profil
    • SFML's website
    • E-mail
Re : Bug avec les threads.
« Réponse #7 le: Juillet 25, 2013, 09:26:38 am »
Y a pas de mutex dans ton code.

Et "un mutex ne marche pas pour une variable" ça ne veut rien dire. Un mutex n'est pas lié à une variable, tu appelles juste des lock et des unlock dans ton code.

Donc, j'ai toujours rien compris. Et vu ta description du problème, je ne suis pas sûr que tu aies tout compris toi non plus.
Laurent Gomila - SFML developer

Lolilolight

  • Hero Member
  • *****
  • Messages: 1232
    • Voir le profil
Ha moi si j'ai compris vu que je suis arrivé à contourner le bug.

Dans mon exemple plus haut, si j'ai un thread qui utilise une variable de la classe truc et que je fais un mutex.lock dans la fonction appelé par mon thread, les autres treads ont toujours accès à cette variable.

Mais j'ai corrigé le problème en initialisant les variables de la classe Truc plus tard c'est à dire dans une autre méthode que le constructeur de la classe Truc.

PS : ce que je n'ai pas compris c'est pourquoi mes autres threads ont accès aux variables de ma classe Truc dans mon exemple plus haut même quand je fais un mutex.lock dans la fonction appelée par mon thread.

PS 2 : si tu veux que je rajoute une classe Thread et un mutex dans mon code là peux être que tu pourras mieux comprendre.
« Modifié: Juillet 25, 2013, 09:39:16 am par Lolilolight »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32498
    • Voir le profil
    • SFML's website
    • E-mail
Citer
Ha moi si j'ai compris vu que je suis arrivé à contourner le bug.
Contourner un bug et comprendre un bug sont deux choses complètement différentes ;)

Citer
Dans mon exemple plus haut, si j'ai un thread qui utilise une variable de la classe truc et que je fais un mutex.lock dans la fonction appelé par mon thread, les autres treads ont toujours accès à cette variable.
Oui, ça c'est normal.
Mais tu veux dire que les autres threads verrouillent aussi le mutex, et que le verrouillage ne bloque pas même si ton autre thread l'a déjà verrouillé ?

Citer
PS 2 : si tu veux que je rajoute une classe Thread et un mutex dans mon code là peux être que tu pourras mieux comprendre.
Oui, j'aimerais bien voir le truc au complet, parce que là sinon on ne va pas s'en sortir.
Laurent Gomila - SFML developer

Lolilolight

  • Hero Member
  • *****
  • Messages: 1232
    • Voir le profil
Ok voici le code complet :
Le fichier .h de la classe Bidule :
class Bidule {
private :
       static Truc& getTruc() {
                Truc *t = new Truc(5);
                return *t;
       }
       static int& getIVar ();
       static Truc &truc;
};
 
Le fichier .cpp de la classe Bidule :
Truc& Bidule::truc = getTruc();
int& Bidule::getIVar () {
       return truc.getIVar();
}
 
Le fichier.h de la classe truc :
class Truc {
private:
         int m_iVar;
public:
        Truc (int iVar);
        int& getIVar();
};
 
Le fichier .cpp de la classe Truc :
Truc::Truc(int iVar) : m_iVar(iVar) {
}
int& Truc::getTruc() {
       return m_iVar;
}
 

Et le main :
Mutex mutex;
void threadFunc () {
       //Problème : le mutex.lock ne marche pas, les autres thread ont accès à la variable iVar!
       mutex.lock();
       int& iVar = Bidule::getIVar();
       mutex.unlock();
}
void main () {
       Thread thread(&threadFunc);
       thread.launch();
}
 

Voilà j'ai mis le code complet et le problème que j'ai en commentaire.

PS : je fais aussi des mutex.lock et unlock dans toutes les fonctions appelées par mes autres thread mais ça ne résouds pas le problème.

PS 2 : je ne sais pas vraiment si le soucis vient de la SFML car j'ai lu sur un autre forum que l'on ne pouvait pas faire ce genre de chose avec le c++98 (impossibilité donc de faire des singletons thread-safe.), mais que le problème serais réglé avec le c++11. (Que j'aimerais bien essayer d'ailleurs mais je n'ai pas encore trouver une version de mingw avec support du c++11 en 32 bits pour tester ça.)
Ma version de mingw en 32 bits possède juste les include et j'ai plein de undefined reference to ... hors que mingw64 possède tout et là je n'ai pas de problèmes.
« Modifié: Juillet 25, 2013, 10:31:07 am par Lolilolight »

Hiura

  • SFML Team
  • Hero Member
  • *****
  • Messages: 4321
    • Voir le profil
    • E-mail
Sans vouloir vexer, tu as meilleur temps d'apprendre un peu plus en détail la concurrence avant de te lancer à l'aveugle dedans.. sinon tu vas finir avec des designs vraiment bancales et ingéreables (comme ici).


A noter que le code que tu nous montres ne peut pas bugger: il n'y a qu'un thread actif donc pas de concurrence.
SFML / OS X developer

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32498
    • Voir le profil
    • SFML's website
    • E-mail
Citer
je ne sais pas vraiment si le soucis vient de la SFML
Moi je sais que non. Tu devrais être un peu plus humble concernant ton propre code. A chaque fois tu viens en criant au bug dans SFML, mais en réalité il y a toujours plein de bourdes dans ton code. T'as pas encore vraiment le niveau d'un expert.

Ensuite je seconde Hiura : ton code ne montre qu'un thread, ça ne nous avance toujours pas à grand chose. Si tu as un problème d'accès concurrent, montre nous cet accès concurrent.

Et enfin concernant les compilos gcc 32 bits, normalement n'importe lequel en version au moins 4.7 supporte C++11 sans problème. Il faut parfois passer explicitement le flag std=c++11 (ou équivalent), mais sinon ça devrait marcher tel quel.
Laurent Gomila - SFML developer

Lolilolight

  • Hero Member
  • *****
  • Messages: 1232
    • Voir le profil
Ce code ne crash pas en effet vu qu'il n'y a qu'un seul thread qui utilise la variable mais je pensais que ça serait assez clair pour la compréhension de mon problème, mais je peux te dire que avec un plus gros code, c'est à dire, avec plusieurs threads et là ou il y a plus de chance d'avoir des accès concurrents, ça bug, je ne peux malheureusement donc pas te montrer avec un plus gros code.

Je ne suis pas rentré en détail dans la programmation multi-thread et la gestion des accès concurrents lors de mes études donc en effet, je ne suis surement pas un expert là dedans.

Mais bon là pour moi c'est clair, désolé.

Bref j'ai résolu le problème en initialisant la variable m_ivar dans une méthode que j'appelle après et non plus dans le constructeur de la classe truc, là, plus de problème d'accès concurrent et je ne broncherai plus ainsi. ^^

« Modifié: Juillet 25, 2013, 12:31:07 pm par Lolilolight »

Hiura

  • SFML Team
  • Hero Member
  • *****
  • Messages: 4321
    • Voir le profil
    • E-mail
Bref j'ai résolu le problème en initialisant la variable m_ivar dans une méthode que j'appelle après et non plus dans le constructeur de la classe truc, là, plus de problème d'accès concurrent et je ne broncherai plus ainsi. ^^

Aïe.

Je me permets juste de me citer:

Citer
sinon tu vas finir avec des designs vraiment bancales et ingéreables (comme ici).

SFML / OS X developer