1

my program is based around a "world" class (essentially "world" contains a 2D vector of the child class "tile" that can hold various variables that can move between different tiles, as well as be erased) that is initiated in main(). main() handles the updating of "world" itself, while the function updateDisplay() displays the contents of "world" on the monitor. updateDisplay() is run by a separate C++11 thread (that is initiated in main()), and accesses "world" through a passed reference.

My problem is that I am encountering a rare crash that occurs because, in the (simplified) code excerpt from updateDisplay() below, the vector world.m_grid[i][j].m_rabbit is occasionally cleared by main() after the "if (!world.m_grid[i][j].m_rabbit.empty())" check in updateDisplay(), but before the subsequent accessing of the m_rabbit[0] vector member, resulting in a "vector subscript out of range" error.

for (int i = 0; i < rows; ++i)
{
    for (int j = 0; j < columns; ++j)
    {

        if (!world.m_grid[i][j].m_rabbit.empty())
        {
            s_rabbit_64.setScale(absTileScale * world.m_grid[i][j].m_rabbit[0].m_size, absTileScale * world.m_grid[i][j].m_rabbit[0].m_size);
            s_rabbit_64.setPosition(x * k + (12 * absTileScale), y * (i - winFocus.y) + (12 * absTileScale));
            window.draw(s_rabbit_64);
        }
    }
}

My question is, how do I go about locking down world.m_grid[i][j].m_rabbit vector so that main() cannot alter it while the updateDisplay() thread is accessing it? I gather this is achieved through use of std::mutex, but I have been unable to find a guide that gives me a good enough understanding of this to apply it to my program. I hope this is clear enough to understand (the program is much larger than this excerpt and I didn't want to do a massive text-dump), please ask for clarification on any points you need.

Thankyou for your attention.

[edit] spelling

ildjarn
  • 62,044
  • 9
  • 127
  • 211
Proply
  • 59
  • 4

2 Answers2

3

Welcome to the wild and wooly world of multithreading. Take a seat; you'll be here for a long time. As in, the rest of your programming career kind of long. It's scary, full of treachery and subtle bugs, and also pays really well if you can do it right :-)

You've done a pretty good job of identifying the specific bug in this case, actually. What you'll want is to have a mutex guarding all accesses and mutations of state that's shared between threads. In your case: lock the mutex in your main thread before clearing the vector, and unlock the mutex after you're done. Similarly, lock the mutex in your processing thread before accessing it, and unlock it when you're done. In this particular case you'll probably end up locking the entire double-for loop you've got going there.

This answer is a pretty good explanation of what the mutex is doing.


Yes, there are faster and more elegant ways of doing things, but let's stick with correctness for now.

Community
  • 1
  • 1
sheu
  • 5,653
  • 17
  • 32
1

You need to identify critical section of your code. From what you posted above, it seems any operation that modifies world.m_grid[i][j].m_rabbit is a critical section.

You then need some kind of synchronization techniques such that only 1 thread can enter particular critical section at any one time (for example mutex).

You need to search the web for some good reading -- or even better find a good programming book and spend some time on the concurrency chapter.

gerrytan
  • 40,313
  • 9
  • 84
  • 99