Every now and again, you run into a piece of code that does the impossible… It always comes down to finding the “misunderstanding” between you and the compiler (or interpreter) on some particular of an instruction. You might have said “halt and catch fire” and the computer might interpret “catch fire” as “stop it from hitting the ground” instead of “combust”.
A little but if Mutex-wrapped code I’ve inherited is insisting on crashing as two threads simultaneously try to work inside a Mutex. Which is impossible: Mutex is short for ‘Mutual Exclusion‘.
This is not for the feint hearted (a symptom of feint heartedness can be programming in Java :-P)
bool queued, loading, loaded;
MutexLock _queueMutex, _loadMutex;
void Supercell::LoadThread::AddSupercell(Supercell* sc)
SuperCell* sc = NULL;
// Have to lock the queue before we begin so that we can
// look at ‘done’ and ‘_cells’ and begin the “wait” process.
while(false == _done && true == _cells.empty())
// Make sure we can lock the work mutex before we pick
// up anything to work on.
// Race-condition elimination; TRY and get the lock but
// if we can’t get it immediately, we won’t do any work.
bool lockedLoad = ( _loadMutex.tryLock() == 0 ) ;
if ( lockedLoad )
sc = _cells.front();
// Release the queue early because works non-trivial time.
if ( lockedLoad )
if ( NULL != sc )
// Now we need to re-lock the queue so we can look
// at “done” and _cells and start the wait loop again.
// When a Renderer destructs, it removes all of its supercells from the loadthread…
void LoadThread::RemoveRendererSuperCells(Renderer* r)
// Lock the queue, prevent the loader from grabbing the next queue entry.
// We also need to wait for the loader to finishing up whatever it might be doing.
// Code to remove all Supercells in _cells which have sc->_renderer == r
for(SuperCellList::iterator it = _cells.begin() ; it != cells.end() ; )
if((*it)->_renderer == r) _cells.remove(it++);
And yet, it still crashes with Thread 8 instead sc->Load while Thread 1 is in RemoveRendererSuperCells .
HOW THE HELL?
I took the “do over” stick to it. I made sure all the derived classes have virtual destructors – not that it should matter; and I switched that std::list for a std::vector
for ( SupercellList::iterator it = _cells.begin() ; it != _cells.end() ; )
if ( (*it)->_renderer == r )
*it = _cells.back() ; // Move the last entry here
_cells.pop_back() ; // Remove the last entry
Similar changes to the Loader … And now it’s a tiny, wee bit faster but gives the visual illusion of being noticeably faster (because of a change to the order in which it renders) … but more importantly, doesn’t crash.
Scratch Ticket #1984: PC and Mac client crashes at Map Screen when clicking navigation buttons.