Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ std::mutex lock() access violation in Visual Studio 2017

When I'm trying to run executable compiled using VS2017 I catch Exception thrown at 0x00007FFF05BC1063 (msvcp140d.dll) in a.exe: 0xC0000005: Access violation reading location 0x0000000000000000. immediately after launching.

After debugging i figured out that it happens when I'm trying to lock static mutex _coutMutex. How can I fix it because when I have compiled using mingw it worked fine. Here is part of my code:

Game.hpp:

#include "Logger.hpp"

class Game
{
public:
    static Logger logger;
};

Game.cpp:

#include "Game.hpp"

Logger Game::logger{ "logs/client", Logger::LoggingLevels::Info, 
  Logger::LoggingLevels::Trace, 2, 100 };

Logger.hpp:

#include <mutex>

class Logger
{
public:
    Logger(std::string path, short consoleLoggingLevel, short 
      fileLoggingLevel, uint32_t count, size_t maxSize);

    enum LoggingLevels : short
    {
        Off = 0,
        Fatal = 1,
        Error = 2,
        Warn = 3,
        Info = 4,
        Debug = 5,
        Trace = 6
    };

void _addToQueue(std::string data);
private:
    static std::mutex _coutMutex;  
};

Logger.cpp:

std::mutex Logger::_coutMutex;

Logger::Logger(std::string path, short consoleLoggingLevel,
   short fileLoggingLevel, uint32_t count, size_t maxSize)
{
    _addToQueue("dd/mm/yyyy hh:mm:ss.sss\n");
}

void Logger::_addToQueue(std::string data)
{
    _coutMutex.lock();
    std::cout << data;
    _coutMutex.unlock();
}

main.cpp:

#include "Logger.hpp"
#include "Game.hpp"

int main()
{
    Game game;
}
like image 871
Stuv7CB Avatar asked Jul 09 '17 16:07

Stuv7CB


1 Answers

As Richard Critten suggests, this must be the global initialisation order problem.

You have 2 global variables, logger and _coutMutex, and these are in a different compilation unit. The order which they are initialized is not defined.

When Logger's constructor runs, _coutMutex is not initialized yet, but _addToQueue wants to use it.

You could have three solutions:

  • Avoid using global objects. Or avoid using global constructors which do something serious (if you remove _addToQueue from logger constructor, it will work).
  • put these global variables into one compilation unit, in correct order
  • add an accessor function for _coutMutex, and define mutex inside of it (as a static variable). Beware of this solution, as it has its drawbacks (speed, thread safety)
like image 169
geza Avatar answered Nov 07 '22 12:11

geza