4

複数のスレッド間で同期したい stl マップがあります。現在、私は...

機能A(地図修正)

void Modify(std::string value)
{
    pthread_mutex_lock(&map_mutex);

    my_map[value] = value;

    pthread_mutex_unlock(&map_mutex);
}

機能B(マップ読み込み)

std::string Read(std::string key)
{
    std::string value;

    pthread_mutex_lock(&map_mutex);

    std::map<std::string, std::string>::iterator it = my_map.find(key);

    pthread_mutex_unlock(&map_mutex);

    if(it != my_map.end())
    {
        return it->second;
    }
    else
    {
        return "DNE";
    }
}

ミューテックスにより、これはすべてのスレッドで同期されます。ただし、マップをまったく変更していない場合でも、関数 B でミューテックスをロックする必要があります。関数 A で my_map オブジェクト自体をロックし、スレッドの同期を維持しながら関数 B でロックしない方法はありますか。このように、関数 A が実行されていない限り、関数 B のすべてのインスタンス/呼び出しは引き続き自由に実行されますか?

ありがとう

4

3 に答える 3

3

コンテナをロックするだけでなく、コンテナへのアクセス、つまりコンテナへのイテレータやポインタもロックする必要があります。これらのアクセスをコードのロックされた領域に移動する必要があります。

std::string Read(std::string key)
{
    std::string value = "DNE";

    pthread_mutex_lock(&map_mutex);

    std::map<std::string, std::string>::iterator it = my_map.find(key);
    if(it != my_map.end())
    {
        value = it->second;
    }

    pthread_mutex_unlock(&map_mutex);

    return value;
}

オブジェクト自体の内部からこれを行う実際的な方法はありません。

于 2012-06-04T20:04:47.460 に答える
1

警告: 私はこれをコンパイルしたりテストしたりしていませんが、過去に同様のことをしました。

ステップ 1 は、次のようにクラスでミューテックスを制御することです。

class Lock {
    public:
        Lock(Mutex& mutex) {
            pthread_mutex_lock(mutex);
        }
        ~Lock(Mutex& mutex) {
            pthread_mutex_unlock(mutex);
        }
};

これにより、たとえば、マップが例外をスローした場合など、あらゆる種類の問題を回避できます。

次に、変更は次のようになります。

void Modify(std::string value)
{
    Lock(map_mutex);    

    my_map[value] = value;
}

参照カウント ロック クラスを作成します。

class RefCntLock {
    private:
        static int count;
        static Lock* lock;

    public:
        RefCountLock(Mutex& mutex) {

             // probably want to check that the mutex matches prior instances.
             if( !lock ) {
                  lock = new Lock(mutex);
                  count++;
             }
        }
        ~RefCountLock() {
             --count;
             if( count == 0 ) {
                 delete lock;
                 lock = NULL;
             }
        }
}; 

(注: 複数のミューテックスを扱うためにこれを一般化するのは簡単です。)

readで、RefCntLock クラスを使用します。

std::string Read(std::string key)
{
    {
        RefCntLock(&map_mutex);

        std::map<std::string, std::string>::iterator it = my_map.find(key);
    }

    if(it != my_map.end())
    {
        return it->second;
    }
    else
    {
        return "DNE";
    }
}

これは、各書き込みはロックを取得しますが、すべての読み取りはロックを共有することを意味します。

于 2012-06-04T19:54:11.823 に答える