2

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

大家好,我无法使用 std::mutex 来防止 main() 更改第二个线程正在访问的变量。在以下示例中(这是我实际程序的大量简化表示),函数 update() 从 main() 中的 std::thread t2 运行。update() 检查向量 world.m_grid[i][j].vec 是否为空,如果不是,则修改包含的值。main() 也访问并偶尔清除此向量,因此如果 main() 在 update() 中的空检查之后但在修改 world.m_grid[i][j].vec[0] 之前清除该向量,您会得到向量下标超出范围错误。我正在尝试使用 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? 并且无法使描述的解决方案适应我的项目,所以如果有人也能帮助我,那将是非常有帮助的。

-感谢您的时间。

[编辑] 拼写

4

2 回答 2

2

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

 ...
 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 在访问数据时会生成一个互斥锁。但是,主线程可以更改代码,因为它对互斥锁一无所知。所以主线程可以简单地改变数据。

于 2013-01-30T05:24:30.363 回答
1

您遇到的问题是您正在使用所谓的客户端同步。换句话说:您有多个线程,并且在每个线程都写入/读取共享资源之前,您必须使用屏障。由于 tune2fs 已经回复,您必须lock_guard<mutex> guard(barrier)在主线程调用之前。

也就是说,实现服务器端同步对您来说会好得多。换句话说,每个(如果有超过 1 行——比如在你的主线程中——你需要发送所有这些)必须由服务器同步(World)。

目前我可以建议使用一种方法void modify(Func<void(vector<int>&)> mutator);World这样您就可以通过这种方法将所有逻辑作为 lambdas(最简单的)发送。在内部modify,您将使用lock_guard拥有mutex的标准World。该解决方案更具可扩展性和安全性(您真的不想查看调用修改向量的代码的所有位置)。

于 2013-01-30T08:07:24.373 回答