-1

I've got an stl map container that I need to be read-only (read: thread-safe) after initialization, to prevent the possibility of one of my program's threads from trying to make a change to it, and thus causing a race condition. this map uses std::make_pair. At present, I have three maps, all declared as static members of class mmapper, implemented the same way, just with different values:

class mmapper {
        public:
                mmapper();
                std::string getKeyFromMap( const int &key1, const int &key2, const int &mid );
                static std::map<RgCodeUidPair, std::string> siteMap;
                static std::map<TPCodeUidPair, std::string> cachedData;
                static std::map<DLpair, std::string> Ddlabel;
        private:
                void createTypeMap();
                void createSiteMap();
                void createDriveLetterMap();
};



typedef std::pair<int, int> TPCodeUidPair;
typedef std::pair<int, int> RgCodeUidPair;
typedef std::pair<int, int> DLpair;
void mmapper::createSiteMap() {
                logger _logger( glob.g_ll, glob.g_logfile );
                _logger.logstream << "Loading Site Map.";
                _logger.log( 0 );
        if ( siteMap.empty() ) {
                siteMap.insert(std::make_pair(std::make_pair(0, 0), "AUS"));
                siteMap.insert(std::make_pair(std::make_pair(0, 1), "AUS2"));
                siteMap.insert(std::make_pair(std::make_pair(1, 0), "DCA"));
                siteMap.insert(std::make_pair(std::make_pair(1, 1), "DCA1"));
                siteMap.insert(std::make_pair(std::make_pair(1, 2), "DCA2"));
                siteMap.insert(std::make_pair(std::make_pair(1, 3), "DCA3"));
                siteMap.insert(std::make_pair(std::make_pair(1, 4), "DCAg"));
                siteMap.insert(std::make_pair(std::make_pair(1, 4), "LAX"));
                siteMap.insert(std::make_pair(std::make_pair(1, 5), "MIA"));
                siteMap.insert(std::make_pair(std::make_pair(1, 6), "TOR"));
                siteMap.insert(std::make_pair(std::make_pair(1, 7), "NYC"));
                siteMap.insert(std::make_pair(std::make_pair(2, 0), "AMS"));
                siteMap.insert(std::make_pair(std::make_pair(2, 1), "AMS1"));
                siteMap.insert(std::make_pair(std::make_pair(2, 2), "AMS2"));
                siteMap.insert(std::make_pair(std::make_pair(2, 3), "AMS3"));
                siteMap.insert(std::make_pair(std::make_pair(2, 4), "LON"));
                siteMap.insert(std::make_pair(std::make_pair(2, 5), "ZUR"));
                siteMap.insert(std::make_pair(std::make_pair(2, 6), "WAR"));
                siteMap.insert(std::make_pair(std::make_pair(3, 0), "HKG"));
                siteMap.insert(std::make_pair(std::make_pair(3, 1), "SGP"));
                siteMap.insert(std::make_pair(std::make_pair(3, 2), "TOK"));
                siteMap.insert(std::make_pair(std::make_pair(3, 3), "SYD"));
        }
}

These are parsed by a single accessor function:

std::string mmapper::getKeyFromMap( const int &key1, const int &key2, const int &mid ) {
        logger _logger( glob.g_ll, glob.g_logfile );
        switch( mid ) {
                case 1: {
                        _logger.logstream << "Retrieving key values for Server Type.";
                        _logger.log( 1 );
                        auto it = cachedData.find(std::make_pair(key1, key2));
                        if( it != cachedData.end() ) {
                                _logger.logstream << "Successfully retrieved key value";
                _logger.log( 1 );
                                return it->second;
                        }
                        else {
                                _logger.logstream << "Failed to retrieve key.";
                _logger.log( 3 );
                                return "ERR";
                        }
                        break;
                }
                case 2: {
                        _logger.logstream << "Retrieving key values for Server Site.";
                        _logger.log( 1 );
                        auto it = siteMap.find(std::make_pair(key1, key2));
                        if( it != siteMap.end() ) {
                                _logger.logstream << "Successfully retrieved key value";
                                _logger.log( 1 );
                                return it->second;
                        }
                        else {
                                _logger.logstream << "Failed to retrieve key.";
                                _logger.log( 3 );
                                return "ERR";
                        }
                        break;
                }
                case 3: {
                        _logger.logstream << "Retrieveing key values for drive label";
                                _logger.log( 1 );
                        auto it = Ddlabel.find( std::make_pair( key1, key2 ));
                        if( it != Ddlabel.end() ) {
                                _logger.logstream << "Successfully retrieved key value";
                                _logger.log( 1 );
                                return it->second;
                        }
                        else {
                                _logger.logstream << "Failed to retrieve key.";
                _logger.log( 3 );
                                return "ERR";
                        }
                        break;
                }
                default:
                        _logger.logstream << "Invalid value passed to mapper! Err 3";
                        _logger.log( 5 );
                        return "ERR";
        }
}

So my question here is, how can I prevent my threads from modifying this thread? I was thinking of having the maps simply be static const but I'm unsure how to implement that with std::pair.

I normally wouldn't care, but this keeps throwing segfaults after ~20 minutes. :(

Here is backtrace:

    at /usr/src/debug/gcc-4.4.7-20120601/obj-x86_64-redhat-linux/x86_64-redhat-linux/libstdc++-v3/include/bits/basic_string.tcc:174
#1  0x000000000040f47c in mmapper::getKeyFromMap (this=0x7fff42554ccf, key1=@0x7fffac012f60, key2=@0x7fffac012f64,
    mid=@0x7fff42554cec) at include/mmapper.cpp:65
#2  0x0000000000436bee in ddrive::readDriveData (this=0x7fff425550b0, data1=
    std::vector of length 576, capacity 1024 = {...}, db=...) at include/drive.cpp:83
#3  0x00000000004162f2 in handle_data(std::vector<int, std::allocator<int> >&) ()
#4  0x0000000000416fd7 in session(boost::shared_ptr<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> > >) ()
#5  0x00000000004249ac in void boost::_bi::list1<boost::_bi::value<boost::shared_ptr<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> > > > >::operator()<void (*)(boost::shared_ptr<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> > >), boost::_bi::list0>(boost::_bi::type<void>, void (*&)(boost::shared_ptr<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> > >), boost::_bi::list0&, int) ()
#6  0x00000000004247bf in boost::_bi::bind_t<void, void (*)(boost::shared_ptr<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> > >), boost::_bi::list1<boost::_bi::value<boost::shared_ptr<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> > > > > >::operator()() ()
Oblivious12
  • 61
  • 1
  • 7
  • Have you used a debugger / inspected a core etc. to see what the call stack was when the segfault happened? – Tony Delroy Sep 05 '14 at 04:14
  • 1
    Why are your maps static? If you make them non-static data members, and make `getKeyFromMap` a `const` member function, it won't be able to modify the maps. But I doubt that'll fix your problem, since the function doesn't currently look like it's modifying them. – Praetorian Sep 05 '14 at 04:17
  • @TonyD I have, but whenever I run it through GDB, the segfault magically ~doesn't happen~. :\ – Oblivious12 Sep 05 '14 at 04:34
  • You should read this post http://stackoverflow.com/a/22617989/2724703. Based on problem symptoms it appears to me that there is some sort of memory corruption which is linked with data racing between thread. Probably Valgrind/Helgrind tool would be useful for you. It appears to me that you are running on Linux.' – Mantosh Kumar Sep 05 '14 at 04:40
  • Even so, can you not enable core file dumping and use gdb post-facto? – Tony Delroy Sep 05 '14 at 05:18
  • I... have no idea how to do that. – Oblivious12 Sep 05 '14 at 11:51

1 Answers1

1

If the mmapper is never changed again after initialization, I can see only two points of failures at mmapper::getKeyFromMap() :

  1. The parameters. All of them are references to external data. If the external data is removed, random exceptions may happen. Change them from const int& to int. A "pass by value" is the best approach for primitive types (check this post).

  2. The logger. Are you sure its implementation is thread-safe? It's internal data are changing very frequently, so it is a good point of failure.

The exception seems to come from basic_string.tcc line 174, that is called by mmapper line 65. Those lines may give you a better clue of the problem.

Community
  • 1
  • 1