Herzlich Willkommen, lieber Gast!
  Sie befinden sich hier:

  Forum » C / C++ (ANSI-Standard) » std::lock_guard (mutex) produziert deadlock

Forum | Hilfe | Team | Links | Impressum | > Suche < | Mitglieder | Registrieren | Einloggen
  Quicklinks: MSDN-Online || STL || clib Reference Grundlagen || Literatur || E-Books || Zubehör || > F.A.Q. < || Downloads   

Autor Thread - Seiten: > 1 <
000
23.05.2018, 11:48 Uhr
LynarStudios



Hey!

Zunächst: Danke, dass du dieses Thema liest und mir versuchst bei meinem Problem zu helfen. Das ganze Thema threading ist ziemlich neu für mich.

Kurze Einführung:

Ich habe vor einigen Monaten eine Game Engine geschrieben, die auch sehr gut läuft und in Spielen bereits verwendet wird. Die Engine baut auf SDL2 auf. Ich möchte nun die Engine thread safe machen, um die Performance zu verbessern und auch mit anderen theoretischen Konzepten rumspielen zu können.

Das Problem:

Das Spiel benutzt intern Zustandswerte, um zu erkennen in welchem Teil des Spieles es sich befindet, wie etwa einen Wert für das Anzeigen des Menüs, oder auch für andere Inhalte des Spieles. Wird der Wert "Asteroid Level" erreicht (ein kleiner Teil des Spieles) wird eine exception geworfen, wenn std::lock_guard aufgerufen wird.

Das Problem im Detail:

Wird das "Asteoriden Level" erreicht, wird eine modelGetDirection() Funktion aufgerufen, die einen 2D Vektor zurück gibt. Diese Funktion nutzt einen lock_guard, um thread safe zu sein. Wenn ich die ganze Anwendung debugge, weiß ich, dass genau bei diesem Aufruf eine exception geworfen wird. Das merkwürdige ist, dass diese Funktion, und somit auch der mutex niemals vorher aufgerufen wird. Jedes Mal, wenn ich das Programm teste crasht das Programm genau an dieser Stelle.

Das ist die Stelle, wo der Debugger in threadx stoppt:

C++:
inline int _Mtx_lockX(_Mtx_t _Mtx)
{   // throw exception on failure
return (_Check_C_return(_Mtx_lock(_Mtx)));
}


Das ist die exception:

Zitat:
Exception thrown at 0x00007FF9181B0B03 (msvcp140d.dll) in SolarLight.exe: 0xC0000005: Access violation reading location 0x00000020000AFF18.

Und das hier sind die eigentlich Code - Abschnitte, von denen ich glaube, dass sie wichtig sind:

mutex struct:

C++:
struct LEMutexModel
{
  // of course there are more mutexes inside here
  mutex modelGetDirection;
};


engine Klasse:

C++:
typedef class LEMoon
{
  private:
    
    LEMutexModel mtxModel;

    // other mutexes, attributes, methods and so on

  public:

    glm::vec2 modelGetDirection(uint32_t, uint32_t);

    // other methods
} *LEMoonInstance;


modelGetDirection() - engine Definition:

C++:
glm::vec2 LEMoon::modelGetDirection(uint32_t id, uint32_t idDirection)
{
  lock_guard<mutex> lockA(this->mtxModel.modelGetDirection);
  glm::vec2 direction = {0.0f, 0.0f};
  LEModel * pElem = this->modelGet(id);
    
  if(pElem == nullptr)
   {pElem = this->modelGetFromBuffer(id);}

  if(pElem != nullptr)
    {direction = pElem->pModel->mdlGetDirection(idDirection);}
  else
  {
    #ifdef LE_DEBUG
      char * pErrorString = new char[256 + 1];
      sprintf(pErrorString, "LEMoon::modelGetDirection(%u)\n\n", id);
      this->printErrorDialog(LE_MDL_NOEXIST, pErrorString);
      delete [] pErrorString;
    #endif
  }
    
  return direction;
}


Das ist die Funktion, wo modelGetDirection() aufgerufen wird:

C++:
void Game::level1ControlShip(void * pointer, bool controlAble)
{
  Parameter param = (Parameter) pointer;
  static glm::vec2 currentSpeedLeft = {0.0f, 0.0f};
  glm::vec2 speedLeft = param->engine->modelGetDirection(MODEL_VERA, LEFT);
  static const double INCREASE_SPEED_LEFT = (1.0f / VERA_INCREASE_LEFT) * speedLeft.x * (-1.0f);
// ... more code, I think that's not important
}


Wie bereits erwähnt: Wenn die Funktion level1ControlShip() aufgerufen wird, wird die Funktion modelGetDirection() aufgerufen. Wird modelGetDirection() aufgerufen wird direkt eine exception geworfen bei dem Versuch diesen lock_guard aufzurufen:

C++:
lock_guard<mutex> lockA(this->mtxModel.modelGetDirection);


Es ist das erste Mal, dass die Funktion modelGetDirection() und somit auch dieser mutex benutzt wird. Was ist also das Problem? Ich sitze schon seit einer Weile an dieser Lösung. Klar ist auch, dass das Programm keine Exception wirft, wenn die Funktion level1ControlShip() nicht aufgerufen wird.

Über jede Hilfe wäre ich sehr, sehr dankbar.

Die Game Engine (nicht das Spiel) ist übrigens ein open source Projekt und auf gitHub verfügbar, sollte ich wichtigen Code vergessen haben:

https://github.com/LynarStudios/LEMoon

Vielen Dank schon einmal!

Gruß,
Patrick

Dieser Post wurde am 23.05.2018 um 11:51 Uhr von LynarStudios editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
001
23.05.2018, 12:32 Uhr
ao

(Operator)


"0xC0000005: Access violation" - das bedeutet, das Programm greift ins Klo. Kann es sein, dass das Mutex-Objekt nicht oder nicht richtig erzeugt wird? Oder schon wieder zerlegt ist?

Wenn ich deinen Code richtig deute, ist _Mtx_t ein Pointer auf einen Mutex. Zeigt _Mtx auf ein gültiges Mutex-Objekt?
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
002
23.05.2018, 12:49 Uhr
LynarStudios



Hey,

Also:

- "mtxModel" ist ein eigener struct, welcher "mutex modelGetDirection;" als variable beinhaltet.

- "mtxModel" wird in der engine (LEMoon)-Klasse als Attribut (nicht als Referenz) geführt, und wird daher nicht im Konstruktor der Klasse explizit erzeugt.


Code:
lock_guard<mutex> lockA(this->mtxModel.modelGetDirection);


ist demnach der aller erste Aufruf, in dem das Attribut "mtxModel" der LEMoon Klasse verwendet wird.

Da ich aber, wie du schon sagst, irgendwo ins "Klo" greife, stimmt hier ja etwas nicht. Die Frage ist aber was? Da der mutex ja ein Klassenattribut ist, sollte es doch keine Probleme geben? Oder sehe ich da irgendetwas nicht?

Danke schon einmal für deine Mühe.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
003
23.05.2018, 16:09 Uhr
ao

(Operator)


OK. Ich vermute mal, bei lock_guard und mutex handelt es sich um std::lock_guard und std::mutex aus dem Thread-Support von stdc++, richtig?

In der Doku zu std::lock_guard::lock_guard (Konstruktor) steht: "The behavior is undefined if m is not a recursive mutex and the current thread already owns m." (Quelle: http://en.cppreference.com/w/cpp/thread/lock_guard/lock_guard)

Ähnliches steht hier: http://en.cppreference.com/w/cpp/thread/mutex/lock

"Undefined behaviour" kann alles bedeuten, auch, dass eine Exception geworfen wird.

Kann irgendwas davon die Ursache sein?


Zitat:
ist demnach der aller erste Aufruf, in dem das Attribut "mtxModel" der LEMoon Klasse verwendet wird.

Aber nicht mtxModel ist das Mutex-Objekt, sondern modelGetDirection. Wenn du das noch woanders verwendest, kann der Mutex sehr wohl schon belegt sein.

Ansonsten zwei Vorschläge:
1. Setz mal einen Breakpoint auf die Zeile mit dem lockA, und wenn du da stehst, untersuch den Kontext. Ist das this in Ordnung? Sehen this->mtxModel und this->mtxModel.modelGetDirection und das Drumherum gut aus? Wenn ja, steppe rein in den Konstruktor und verfolge weiter, was passiert.

2. Bau ein kleines Programm, das nur den lock_guard verwendet und nichts drumherum. Wenn das auch abstürzt, machst du irgendwas dabei falsch. Wenn du nicht weiterkommst, poste dieses Programm vollständig hier. Wenn das nicht abstürzt, steckt der Fehler woanders, möglicherweise ganz woanders, und tritt hier nur zu Tage.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
004
25.05.2018, 13:03 Uhr
LynarStudios



Hey,

Einen Breakpoint hatte ich bereits gesetzt auf die besagte Zeile! Ich erkenne keine ungewöhnlichen Werte:

Code:
-        this->mtxModel.mtxModelGetDirection    {...}    std::mutex
-        std::_Mutex_base    {_Mtx_storage={_Val=8.487983163861e-314#DEN _Pad=0x00007ff9190aea28 "" } }    std::_Mutex_base
-        _Mtx_storage    {_Val=8.487983163861e-314#DEN _Pad=0x00007ff9190aea28 "" }    std::_Align_type<double,80>
        _Val    8.487983163861e-314#DEN    double
-        _Pad    0x00007ff9190aea28 ""    char[80]
        [0]    0 '\0'    char
        [1]    0 '\0'    char
        [2]    0 '\0'    char
        [3]    0 '\0'    char
        [4]    4 '\x4'    char
        [5]    0 '\0'    char
        [6]    0 '\0'    char
        [7]    0 '\0'    char
        [8]    24 '\x18'    char
        [9]    -1 'ÿ'    char
        [10]    10 '\n'    char
        [11]    0 '\0'    char
        [12]    32 ' '    char
        [13]    0 '\0'    char
        [14]    0 '\0'    char
        [15]    0 '\0'    char
        [16]    0 '\0'    char
        [17]    0 '\0'    char
        [18]    0 '\0'    char
        [19]    0 '\0'    char
        [20]    1 '\x1'    char
        [21]    0 '\0'    char
        [22]    0 '\0'    char
        [23]    0 '\0'    char
        [24]    34 '\"'    char
        [25]    5 '\x5'    char
        [26]    -109 '“'    char
        [27]    25 '\x19'    char
        [28]    3 '\x3'    char
        [29]    0 '\0'    char
        [30]    0 '\0'    char
        [31]    0 '\0'    char
        [32]    88 'X'    char
        [33]    -1 'ÿ'    char
        [34]    10 '\n'    char
        [35]    0 '\0'    char
        [36]    0 '\0'    char
        [37]    0 '\0'    char
        [38]    0 '\0'    char
        [39]    0 '\0'    char
        [40]    0 '\0'    char
        [41]    0 '\0'    char
        [42]    0 '\0'    char
        [43]    0 '\0'    char
        [44]    7 '\a'    char
        [45]    0 '\0'    char
        [46]    0 '\0'    char
        [47]    0 '\0'    char
        [48]    112 'p'    char
        [49]    -1 'ÿ'    char
        [50]    10 '\n'    char
        [51]    0 '\0'    char
        [52]    80 'P'    char
        [53]    0 '\0'    char
        [54]    0 '\0'    char
        [55]    0 '\0'    char
        [56]    0 '\0'    char
        [57]    0 '\0'    char
        [58]    0 '\0'    char
        [59]    0 '\0'    char
        [60]    1 '\x1'    char
        [61]    0 '\0'    char
        [62]    0 '\0'    char
        [63]    0 '\0'    char
        [64]    34 '\"'    char
        [65]    5 '\x5'    char
        [66]    -109 '“'    char
        [67]    25 '\x19'    char
        [68]    1 '\x1'    char
        [69]    0 '\0'    char
        [70]    0 '\0'    char
        [71]    0 '\0'    char
        [72]    -48 'Ð'    char
        [73]    -1 'ÿ'    char
        [74]    10 '\n'    char
        [75]    0 '\0'    char
        [76]    0 '\0'    char
        [77]    0 '\0'    char
        [78]    0 '\0'    char
        [79]    0 '\0'    char



Oder übersehe ich hier etwas?

Ich habe ein Test Framework, in dem ich nur die Engine teste. Dort kriege ich keine Fehler beim Aufrufen dieser Funktion!

Ich arbeite mit Visual Studio 2017. Ich kann das Projekt exportieren und irgendwo hochladen?
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
Seiten: > 1 <     [ C / C++ (ANSI-Standard) ]  


ThWBoard 2.73 FloSoft-Edition
© by Paul Baecher & Felix Gonschorek (www.thwboard.de)

Anpassungen des Forums
© by Flo-Soft (www.flo-soft.de)

Sie sind Besucher: