c++ - 无法获取 std::mutex 来正确保护线程访问

标签 c++ multithreading class c++11 mutex

[使用 Visual Studio Professional 2012 的 C++]

大家好,我在使用 std::mutex 来阻止 main() 更改第二个线程正在访问的变量时遇到问题。在下面的示例中(这是我的实际程序的大规模简化表示),函数 update() 从 main() 中的 std::thread t2 运行。 update() 检查 vector world.m_grid[i][j].vec 是否为空,如果不是,则修改包含的值。 main() 也会访问并偶尔清除该 vector ,因此,如果 main() 在 update() 中的空检查之后但在修改 world.m_grid[i][j].vec[0] 之前清除该 vector ,您会得到 vector 下标超出范围错误。我试图使用 std::mutex 来防止这种情况发生,方法是在 update() 空检查之前锁定屏障,并在 world.m_grid[i][j].vec[0] 被 update() 修改后释放它,在广泛浏览互斥体教程和示例后,我无法理解为什么以下内容没有达到预期的效果:

#include <cstdlib>
#include <thread>
#include <mutex>
#include <vector>
using namespace std;

mutex barrier;

class World
{
public:
    int m_rows;
    int m_columns;
    class Tile
    {
    public:
        vector<int> vec;
        int someVar;
    };

    vector<vector<Tile> > m_grid;
    World (int rows = 100, int columns = 200): m_rows(rows), m_columns(columns), m_grid(rows, vector<Tile>(columns)) {}
};

void update(World& world)
{
    while (true)
    {
        for (int i = 0; i < world.m_rows; ++i)
        {
            for (int j = 0; j < world.m_columns; ++j)
            {
                if (!world.m_grid[i][j].vec.empty())
                {
                    lock_guard<mutex> guard(barrier);
                    world.m_grid[i][j].vec[0] += 5;
                }
            }
        }
    }
}

int main()
{
    World world;
    thread t2(update, ref(world));
    while (true)
    {
        for (int i = 0; i < world.m_rows; ++i)
        {
            for (int j = 0; j < world.m_columns; ++j)
            {
                int random = rand() % 10;
                if (world.m_grid[i][j].vec.empty() && random < 3) world.m_grid[i][j].vec.push_back(1);
                else if (!world.m_grid[i][i].vec.empty() && random < 3) world.m_grid[i][j].vec.clear();
            }
        }  
    } 
t2.join();
return 0;              
}

我一定错过了一些基本的东西。理想情况下,解决方案只是锁定 world.m_grid[i][j] (让 main() 可以访问 world.m_grid 的其余部分),我认为这将涉及在“Tile”类中包含互斥锁,但我遇到了与此处描述的问题相同:Why does std::mutex create a C2248 when used in a struct with WIndows SOCKET?并且无法将所描述的解决方案适应我的项目,因此如果有人也能够帮助我,那将会非常有帮助。

-感谢您的宝贵时间。

[编辑]拼写

最佳答案

当您访问数组时,您还需要在主函数中锁定互斥锁:

 ...
 for (int j = 0; j < world.m_columns; ++j) {
      lock_guard<mutex> guard(barrier);
      int random = rand() % 10;
      if (world.m_grid[i][j].vec.empty() && random < 3) world.m_grid[i][j].vec.push_back(1);
      else if (!world.m_grid[i][i].vec.empty() && random < 3) world.m_grid[i][j].vec.clear();
}
...

使用互斥体,您需要保护对数据的所有访问。到目前为止,在您的代码中,线程 2 在访问数据时会生成一个互斥体。然而,主线程可以更改代码,因为它不知道有关互斥体的任何信息。所以主线程可以简单地改变数据。

关于c++ - 无法获取 std::mutex 来正确保护线程访问,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14597092/

相关文章:

c# - 如何使用 .NET Action 执行参数数量未知的方法?

ios - 核心数据替代方案

Python - 定义对象返回值

c++ - 程序将不再编译

c++ - Windows API 中的逻辑坐标和设备坐标混淆

c++ - 'std::pair<std::_Rb_tree_iterator<_Val>, bool> std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_insert_unique 需要

java - 在并发 HashMap 中重新散列期间检索

c++ - GCC 原子 shared_ptr 实现

c# - 带 ICommand 和 OnPropertyChanged 的​​ WPF 控件可见性

java - 内部类的目的是什么