2

[Visual Studio Professional 2012 を使用した C++]

こんにちは、私は std::mutex を使用して main() が 2 番目のスレッドがアクセスしている変数を変更するのを防ぐのに問題があります。次の例 (実際のプログラムを大幅に簡略化したもの) では、関数 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] をロックダウンするだけで (残りの world.m_grid は main() にアクセスできるようにします)、クラス「Tile」にミューテックスを含める必要があると思いますが、ここで説明されているのと同じ問題: WINdows SOCKET を使用する構造体で使用すると、std::mutex が C2248 を作成するのはなぜですか? 説明されているソリューションを私のプロジェクトに適応させることができなかったので、誰かが私を助けることができれば非常に役に立ちます.

-お時間をいただきありがとうございます。

[編集] つづり

4

2 に答える 2

2

配列にアクセスするときは、メイン関数でもミューテックスをロックする必要があります。

 ...
 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ので、このメソッドを介してすべてのロジックをラムダ (最も簡単) として送信できます。内部では、所有者をmodify使用して標準を使用します。このソリューションは、はるかにスケーラブルで安全です(ベクトルを変更するコードを呼び出すすべての場所を実際に確認する必要はありません)。lock_guardmutexWorld

于 2013-01-30T08:07:24.373 に答える