2009-07-16 16 views
3

データを格納するために複数のスレッドで使用されるstd :: mapがあります。マップはこのように宣言された各スレッドからstd :: mapの値へのポインタ

std::map<int, Call> calls; 

、Iは、相互排他ロックを取得し、そのスレッドに属しているオブジェクトへのポインタ又は参照を取得し、ミューテックスのロックを解除しなければなりません。各オブジェクトは1つのスレッドだけで使用されるため、そのあとでオブジェクトを変更できます。スレッドが消えるとすぐに、マップ内の対応するペアも削除されます。

これを実装する最良の方法を知りたいと思います。私は2つの方法を考えていた:私はこの1つを知っている

1)

は傍若無人クレイジーになりますが、それでも

std::map<int, Call> calls; 
... 

{ 
    mutex.lock(); 
    Call* callptr = &calls[id]; 
    mutex.unlock(); 

    // use callptr 
} 

または2)私はこの1つはより賢明に見えると思います

std::map<int, std::auto_ptr<Call> > calls; 

... 

{ 
    mutex.lock(); 
    std::auto_ptr<Call> callptr = map[id]; 
    mutex.unlock(); 

    // use callptr 

    mutex.lock(); 
    map[id] = callptr; 
    mutex.unlock(); 
} 

スレッド実際には別のDLLで作成され、私はそのコードを持っていません。私が今書いているこのDLLは、そのDLLによってインポートされて使用されます。したがって、std :: mapのみで実装する必要がありますが、これらのメソッドのいずれかがOKか、安定させる方法があるかどうかは誰にでも分かります。

おかげ

+0

Callアイテムへのポインタを取得することはできますが、実際のインスタンスをマップオブジェクトに入れているので、std :: mapは内部的に他の場所にコピーすることを決定することがあります。つまり、ポインタはもはや有効ではなく、解放されたメモリを指し示す可能性があります。現時点では解決策は考えられませんが、これはうまくいかないことをお知らせしたいと思います。 – arke

答えて

5

あなたはイテレータを使用する必要があります。マップ内のオブジェクトの寿命が不確定であるため、ポインタと

mutex.lock(); 

std::map<int, Call>::iterator callptr = calls.find(id); 
callptr->second.foo(); 
... 

mutex.unlock(); 

あなたの最初のソリューションは、問題がある - ツリーがリバランスされたときに、それを移動させてもよいです要素が挿入または削除されたとき。そのコピーコンストラクタとoperator=が実際にコピーしない主な理由 - std::auto_ptrstd::mapmapped_typeの要件を満たしていないため、

あなたの第二の溶液は、まったく動作しません。おそらく、コンパイラエラーは発生しませんが、実行時に非常に奇妙な動作が発生します。

+0

イテレータの提案をありがとう、Pavel。そして私はスマートなポインタやコンテナについては知らなかった。 – Sahas

+8

申し訳ありません、あなたは間違っています。 std :: map内のオブジェクトの存続期間は、挿入された時点から開始され、削除された時点またはマップが削除された時点で終了します。再バランスは内部ノードポインタを変更しますが、キーも値も受け付けません。 – MSalters

2

STLコンテナにauto_ptrを使用しないでください。しないでください。実装者は、コンパイルエラーを実際に試してみる必要があります。標準のコンテナは物事をコピーする傾向があります。これはauto_ptrでは非常に間違っています。

3

私によるとThread Local storageはあなたにとって最良の選択肢です。

スレッド固有のデータが必要な場合は、スレッドローカルストレージを使用して、マップロックおよびミューテックスロックの必要性を完全に排除できます。

+0

はい、私は知っていますが、残念ながらスレッドはコードを持たない別のDLLで作成されるため、できません。 – Sahas

+0

これは問題ではありません。スレッドごとに一度ではなく、プロセスごとに一度TlsAllocを呼び出す必要があります。 – MSalters

関連する問題