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 40316 fois)

0 Membres et 1 Invité sur ce sujet

Lolilolight

  • Hero Member
  • *****
  • Messages: 1232
    • Voir le profil
Pourtant, j'instancie tout dans le thread principale (le main), donc, normalement, tout est bien instancier avec l'ordre dans lequel j'écris le code, mais ici, je viens de rajouter, un pnj à mon word, et quand je veux récupérer le nom du pnj dans le constructeur, paf, plantage!

Voici un petit bout de code qui montre le problème :

La classe qui contient le 1er thread (en variable membre.) :

#include "network.h"

using namespace sf;
using namespace std;

SrkServer::SrkServer(int nbChannels) : m_thread(&SrkServer::run, this)
{
    this->nbChannels = nbChannels;
    running = false;
    Pnj *pnj = new Pnj (Vec2f (500, 500), Vec2f (50, 100), Entity::E_PNJ, "Mafus");
    UpsMapLoader loader("Maps/test.upsmap");
    Map *map = new Map();
    if (loader.createMap(*map,map->getLightManager(), map->getImageManager())) {
        map->gridMap->addPnj(pnj);
        World::addMap(map);
    } else {
        delete map;
    }
    ostringstream oss;
    oss<<"Ho, un nouveau!  Bienvenue dans le monde de Dorikasa!!! Voici votre première quête!";
    oss<<"Les sphérix sont des monstres venu du des Sorokiens, pouvais vous m'en tuer, 10 suffiront.";
    oss<<"Ces monstres mécanique ont le malheur de toujours piétiner mes cultures.";
    Quest* quest = new Quest (oss.str(), 5000);
    pnj->addQuest(quest);

}
void SrkServer::startSrv(int portTCP, int portUDP) {
    for (int i = 0; i < nbChannels; i++) {
        SrkChannel *channel = new SrkChannel(*this, "Channel "+conversionIntString(i+1));
        channels.push_back(channel);

    }
    for (unsigned int i = 0; i < channels.size(); i++) {
        channels[i]->start();
    }
    if (!running) {

        if (!udpSocket.bind(portUDP) == Socket::Done) {
            cerr<<"Impossible d'écouter sur ce port : "<<portUDP<<endl;
        } else {
            selector.add(udpSocket);
        }
        if (!listener.listen(portTCP) == Socket::Done) {
            cerr<<"Impossible d'écouter sur ce port : "<<portTCP<<endl;
        } else {
            cout<<"Server started!"<<endl;
            selector.add(listener);
            m_thread.launch();
        }

    } else {
        cout<<"Server already started!"<<endl;
    }

}
 

Et celle qui contient le second thread en variable membre :

#include "srkchannel.h"
#include "user.h"
#include "../IA/ia.h"
using namespace std;
using namespace sf;
SrkChannel::SrkChannel(SrkServer &server, string name) : server(server), name (name), m_thread(&SrkChannel::run, this)
{
     this->map = World::getMap("Map test");
    BoundingRectangle mZoneInf(200, 200, 500, 500);
    int posX, posY;
    Vec2f isoCoords;
    do {
        posX = rand() % (int) mZoneInf.getWidth();
        posY = rand() % (int) mZoneInf.getHeight();
        isoCoords = Math::convertTo2DIsoCoords(Vec2f (posX, posY) - mZoneInf.getPosition());
        isoCoords += mZoneInf.getPosition();
    } while (map->gridMap->getGridCellAt(isoCoords) == NULL || !map->gridMap->getGridCellAt(isoCoords)->isPassable());

    BoundingPolygon mZone;
    Vec2f** points = new Vec2f*[4];
    points[0] = new Vec2f(mZoneInf.getPosition());
    Vec2f tmp1 = Math::convertTo2DIsoCoords(Vec2f(mZoneInf.getWidth(), 0));
    points[1] = new Vec2f (tmp1 + mZoneInf.getPosition());
    Vec2f tmp2 = Math::convertTo2DIsoCoords(Vec2f(mZoneInf.getWidth(), mZoneInf.getHeight()));
    points[2] = new Vec2f (tmp2 + mZoneInf.getPosition());
    Vec2f tmp3 = Math::convertTo2DIsoCoords(Vec2f (0, mZoneInf.getHeight()));
    points[3] = new Vec2f (tmp3 + mZoneInf.getPosition());
    for (unsigned int i = 0; i < 4; i++) {
        mZone.addPoint(points[i]);
    }
    Monster *m = new Monster (isoCoords, mZoneInf, mZone, 1, 100);
    m->setCenter(isoCoords);

    Time t = seconds(5.f);
    m->setTime(t);
    monsters.push_back(m);
    map->gridMap->getPnj("Mafus")->getQuests()[0]->addMonsterToKill(m, 10);
    tmpDist = 0;
    running = false;
}
void SrkChannel::start () {
    m_thread.launch();
}
 

J'ai un plantage à cette ligne-ci :

map->gridMap->getPnj("Mafus")->getQuests()[0]->addMonsterToKill(m, 10);
 

Et le débugueur m'afficher une erreur, vraiment bizarre. :/

#0 6FC83FAA ??() (D:\Projets-c++\SorrokSrv\bin\Debug\libstdc++-6.dll:??)
#1 ?? 0x004456d5 in Pnj::getName (this=0x440b02 <GridMap::getPnj(std::string)+210>) (D:\Projets-c++\SorrokSrv\world\pnj.cpp:13)
#2 015DA66C ?? () (??:??)
#3 FEEEFEEE ?? () (??:??)
#4 FEEEFEEE ?? () (??:??)
#5 FEEEFEEE ?? () (??:??)
#6 FEEEFEEE ?? () (??:??)
#7 FEEEFEEE ?? () (??:??)
#8 FEEEFEEE ?? () (??:??)
#9 FEEEFEEE ?? () (??:??)
#10 FEEEFEEE ?? () (??:??)
#11 FEEEFEEE ?? () (??:??)
#12 FEEEFEEE ?? () (??:??)
#13 FEEEFEEE ?? () (??:??)
#14 FEEEFEEE ?? () (??:??)
#15 FEEEFEEE ?? () (??:??)
#16 FEEEFEEE ?? () (??:??)
#17 FEEEFEEE ?? () (??:??)
#18 FEEEFEEE ?? () (??:??)
#19 FEEEFEEE ?? () (??:??)
#20 FEEEFEEE ?? () (??:??)
#21 FEEEFEEE ?? () (??:??)
#22 FEEEFEEE ?? () (??:??)
#23 FEEEFEEE ?? () (??:??)
#24 FEEEFEEE ?? () (??:??)
#25 FEEEFEEE ?? () (??:??)
#26 FEEEFEEE ?? () (??:??)
#27 FEEEFEEE ?? () (??:??)
#28 FEEEFEEE ?? () (??:??)
#29 FEEEFEEE ?? () (??:??)

PS : je fais un test sur le nom du pnj pour récupérer le pnj dans la grille.
« Modifié: Août 07, 2013, 12:52:15 pm par Lolilolight »

Lolilolight

  • Hero Member
  • *****
  • Messages: 1232
    • Voir le profil
Non c'est bon j'ai trouvé en ce qui concerne le plantage j'avais inversé 2 arguments dans une fonction..., pour récupérer le pnj de mon vector.

Mais quand je mets ça :
for (int i = 0; i < nbChannels; i++) {
     SrkChannel *channel = new SrkChannel(*this, "Channel "+conversionIntString(i+1));
     channels.push_back(channel);
}
 

Dans le constructeur de SrkServer, c'est là que ça plante mais ça ne plante que en lançant le débugueur et je ne comprends pas pourquoi. :/

Du coup pour débuguer je suis obligé de le mettre dans la méthode startSrv, pas que ça me pose problème mas bon.^^

cobra.one

  • Newbie
  • *
  • Messages: 26
    • Voir le profil
De toute façon selon le message d'erreur que tu nous avais indiqué, tu as un bout de code qui tente d'accéder à la méthode getCenter d'une CellMap qui n'est pas initialisée au moment où l'appel est effectué... ça ne doit pas être bien difficile à retrouver dans le code... :-\

Lolilolight

  • Hero Member
  • *****
  • Messages: 1232
    • Voir le profil
Bah je trouve pas, j'ai initialisé toutes mes CellMap avec le pointeur NULL dans mon std::vector, donc, il ne devrait pas y avoir de CellMap qui ne soit pas initialisée. :/


Cpl.Bator

  • Hero Member
  • *****
  • Messages: 540
    • Voir le profil
 Tes titres de topic ne sont pas explicites, celui qui ne connais pas la SFML pense qu'elle est bourrée de bugs alors que le problème c'est l'interface chaise / clavier.
Tu devrais faire attention à ce point, ne serait ce que par respect pour l'auteur de la librairie qui le fait à titre gracieux & c'est précieux ;)

cobra.one

  • Newbie
  • *
  • Messages: 26
    • Voir le profil
Bah je trouve pas, j'ai initialisé toutes mes CellMap avec le pointeur NULL dans mon std::vector, donc, il ne devrait pas y avoir de CellMap qui ne soit pas initialisée. :/



 :o

J'ai bien lu ? Tu as donc des CellMap* stockées dans un std::vector, qui valent NULL, et tu tentes d'appeller des méthodes dessus ?

Lolilolight

  • Hero Member
  • *****
  • Messages: 1232
    • Voir le profil
Non, je fais un test (if cellMap != NULL) avant d'appeler des méthode dessus mais apparemment c'est pas NULL mais cette valeur bizarre (0xabababab) que mes pointeurs ont, et je comprends pas pourquoi. (On dirait que je les initialise à NULL mais que la valeur du pointeur change dans la méthode run de mon second thread hors que je ne change pas mes pointeurs entre temps.)

J'ai pensé à un accès concurrant mais même en mettant des mutex tout partout, ça ne résous pas le problème.

Je pencherai donc plutôt pour un bug avec gdb (le débugueur de code::block.) ou alors un bug avec les threads mais au niveau OS plutôt, mais je dirai gdb plutôt vu que ça ne plante pas quand je lance pas le débugueur.
Bref il faudra que je prenne le temps de test ça sous linux avec valgind peut être que là j'aurai plus d'infos.
« Modifié: Août 08, 2013, 12:32:47 pm par Lolilolight »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32498
    • Voir le profil
    • SFML's website
    • E-mail
Et au fait, pourquoi tu ne nous montres pas la fonction qui plante (GridMap::getPath) ?
Laurent Gomila - SFML developer

Lolilolight

  • Hero Member
  • *****
  • Messages: 1232
    • Voir le profil
Ok, j'aurai pu faire une fonction récursive aussi pour getPath :

vector<Vec2f> GridMap::getPath (Vec2f startPos, Vec2f finalPos) {

    vector<Vec2f> positions;
    positions.push_back(startPos);
    Vec2f currentPos = getGridCellAt(startPos)->getCenter();

    vector<CellMap*> children;
   //Si le joueur a cliqué sur une case ou il y a collision, on recherche la case qui est le plus près de la collision.
    while (!getGridCellAt(finalPos)->isPassable()) {

        vector<CellMap*> children = getNeightbours(getGridCellAt(finalPos), true);

        int distMin = children[0]->getCenter().computeDist(getGridCellAt(startPos)->getCenter());
        int indMin = 0;
        for (unsigned int i = 1; i < children.size(); i++) {
            int dist = children[i]->getCenter().computeDist(getGridCellAt(startPos)->getCenter());
            if (dist < distMin) {
                distMin = dist;
                indMin = i;
            }
        }
        finalPos = children[indMin]->getCenter();
    }


    //Tant qu'on est pas arrivé sur la case finale.
    while (getGridCellAt(currentPos) != getGridCellAt(finalPos)) {
        //On recherche les cases fils. (ou voisines.)

        CellMap *parent = getGridCellAt(currentPos);
        parent->setTraveled(true);
        vector<CellMap*> children = getNeightbours(parent, false);
        unsigned int j = 0;
        while (j < children.size() && children[j]->isTraveled())
            j++;
       //On recherche la case la plus proche de la position finale et on l'ajoute au path.
        int distMin = children[j]->getCenter().computeDist(finalPos);
        int indMin = j;
        for (unsigned int i = j+1; i < children.size(); i++) {
            if (!children[i]->isTraveled()) {
                int dist = children[i]->getCenter().computeDist(finalPos);
                if (dist < distMin) {
                    distMin = dist;
                    indMin = i;
                }
            }
        }

        positions.push_back(children[indMin]->getCenter());
        parent = children[indMin];
        currentPos = parent->getCenter();

    }
    positions.pop_back();
    positions.push_back(finalPos);
    for (unsigned int i = 0; i < casesMap.size(); i++) {
        if (casesMap[i] != NULL)
            casesMap[i]->setTraveled(false);
    }
    return positions;
}
 

Cette fonction utilise une autre fonction :

//Récupère les cases voisines à la case donnée. (si getOnCellPassable vaut tru ça renvoie aussi les cases ou il y a collision.)
vector<CellMap*> GridMap::getNeightbours(CellMap *cell, bool getCellOnPassable) {
    Vec2f coords = cell->getCoords();
    vector<CellMap*> neightbours;

    for (int i = coords.x - 1; i <= coords.x + 1; i++) {
        for (int j = coords.y - 1; j <= coords.y + 1; j++) {
            if (!(i == coords.x && j == coords.y)) {
                Vec2f neightbourCoords(i, j);
                CellMap *neightbour = getGridCellAtFromCoords(neightbourCoords);
                if (neightbour != NULL) {
                    if (getCellOnPassable)
                        neightbours.push_back(neightbour);
                    else if (neightbour->isPassable())
                        neightbours.push_back(neightbour);
                }
            }
        }
    }
    return neightbours;
}
 
Pourtant je test bien si mes cases sont pas vide avant de les ajouté au vecteur, mes cases sont vide si il n'y a rien dessus sur la map et donc si il n'y a rien ou bien si il y a collision le monstre ne peux pas se déplacer dessus.

« Modifié: Août 08, 2013, 01:55:24 pm par Lolilolight »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32498
    • Voir le profil
    • SFML's website
    • E-mail
Et la ligne 425, c'est laquelle ?

Citer
Pourtant je test bien si mes cases sont pas vide avant de les ajouté au vecteur
C'est pas le problème, le debugger dit que tu accèdes à de la mémoire non-initialisée, pas à un pointeur nul. Donc je pencherai plutôt pour un accès hors bornes, dans l'un des tableaux renvoyés par la fonction getNeightbours.

PS : neighbour n'a pas de "t".
« Modifié: Août 08, 2013, 01:57:23 pm par Laurent »
Laurent Gomila - SFML developer

Lolilolight

  • Hero Member
  • *****
  • Messages: 1232
    • Voir le profil
C'est celle-ci :

int distMin = children[j]->getCenter().computeDist(finalPos);
 

Il me dit que children[j] n'est pas initialisé. (Ce code tourne dans un thread.)
« Modifié: Août 08, 2013, 02:02:09 pm par Lolilolight »

Lolilolight

  • Hero Member
  • *****
  • Messages: 1232
    • Voir le profil
Bon je pense que y'avais bien un accès hors borne, car, j'ai oublié un petit j-- :

while (j < children.size() && children[j]->isTraveled())
            j++;
        j--;
 

En effet si la taille du vecteur vaut 1, quand il va rentrer dans la boucle j va valoir 1 et c'est en dehors du vecteur donc je dois faire un j--;

Mais maintenant j'ai une autre erreur :
#0 ?? CellMap::getCenter (this=0x1800dd49) (D:\Projets-c++\SorrokSrv\world\mapCell.cpp:91)
#1 004437E9 GridMap::getPath(this=0x2d20160, startPos=..., finalPos=...) (D:\Projets-c++\SorrokSrv\world\gridMap.cpp:459)
#2 0042E867 SrkChannel::run(this=0x2dc7638) (D:\Projets-c++\SorrokSrv\NetworkEngine\srkchannel.cpp:78)
#3 011CA678 ?? () (??:??)
#4 ?? ?? () (??:??)

Toujours à cette même ligne.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32498
    • Voir le profil
    • SFML's website
    • E-mail
Tu es sûr que c'est la même ligne ? Maintenant il plante sur la ligne 459.
Laurent Gomila - SFML developer

Lolilolight

  • Hero Member
  • *****
  • Messages: 1232
    • Voir le profil
J'ai changer mon code depuis mes anciens post et j'ai rajouté un truc donc ce n'est plus la même ligne que avant dans le fichier mais c'est exactement à la même ligne de code.

A priori mes this sont valide là pourtant donc c'est surement ailleurs que ça pante.
J'ai essayer de mettre des mutex.lock et unlock dans cette fonction mais ça ne résoud pas le problème.

Bon j'ai rajouté ça pour être sur que j ne sois pas plus petit que 0 non plus mais ça ne résous pas le crash, maintenant ça crash tout le temps que ça soit avec le débugueur ou pas. :o

while (j < children.size() && children[j]->isTraveled())
            j++;
        j--;
        j = (j < 0) ? 0 : j;
 
« Modifié: Août 08, 2013, 03:49:49 pm par Lolilolight »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32498
    • Voir le profil
    • SFML's website
    • E-mail
Le this a l'air bizarre, même si c'est moins évident. Il n'est pas du tout dans la même plage d'addresse que les autres this.

Mets un point d'arrêt sur la ligne qui plante, et inspecte les membres de children[j] (du coup il faudra sans doute que tu le mettes dans une variable locale d'abord). S'ils sont tous choucroutés, c'est que tu as encore une instance moisie.
Laurent Gomila - SFML developer