スレッドとコンテナを共有する際の注意点とは?

このQ&Aのポイント
  • 複数のスレッドでひとつのコンテナを共有する場合の注意点について教えてください。
  • クラスにmapをメンバとして持たせ、更新・ダンプのメソッドを別々のスレッドとして起動させる方法についても教えてください。
  • mapを更新する際にイテレータを再取得しないと問題が生じる可能性についても知りたいです。
回答を見る
  • ベストアンサー

スレッドとコンテナ

ひとつのコンテナを複数のスレッドで共有する場合について教えていただきたいです。 例: -------------------------------------------------- map Aを更新するスレッドthr1、 map Aのおおよその状況をファイルにダンプするスレッドthr2、 というコードを記述したいです。 thr2について、「おおよそ」というのは、thr1がAをどんどん更新(insert, erase)するので、 イテレータ取得した時刻やイテレータを++したタイミングに影響を受けて、Aの特定の瞬間を丸々きれいにダンプできなくてもイイや別に、という意味です。 (丸々ならよりよいのですが。) -------------------------------------------------- クラスにmapをメンバとして持たせ、同様に更新・ダンプのメソッドも持たせ、 このメソッドを別々のスレッドとして起動させて、参照はイテレータを利用すれば実現できるかなぁ、と思っていたのですけど、調べると「だめかも」しれない、と思えてきました。 先ずはこの点、どうなのでしょうか?★ mapを更新すると、その瞬間、イテレータを再度取得しなおさないと、未定義の動作かアクセス違反的な難しいことになりそうです。 今回の例を実現するには、いちいちmapをロックしないとならないでしょうか?★

質問者が選んだベストアンサー

  • ベストアンサー
回答No.1

> 今回の例を実現するには、いちいちmapをロックしないとならないでしょうか?★ lockだけで十分だろうか? たとえば thr2が begin(),end() を手に入れた直後にthr1がclear()したら、 thr2が入手したiteratorはつかえなくなってますよね。

nico60000
質問者

お礼

epistemeさん、いつもありがとうございます。 mapの更新アクセスの際はロックしてからの利用とします。 参照するスレッドはロックしてから複製したmapに対して参照をかけることにします。

関連するQ&A

  • STL mapからの要素の削除

    mapより特定の値を持つ要素を削除したいのですが、上手くいきません。 下のようなコードで実現しようとしたのですが、eraseを呼んだ次のループでもう一度eraseを呼んで実行時エラーとなってしまうようです。 erase後のイテレータが指す値が悪いのではないかとは思うのですが、実際に何が悪いのかご存知の方がいらっしゃればアドバイスをお願いいたします。 string s[20]; char c='a'; map<string,bool> m; //mapへの要素の挿入 for(int j=0;j<20;j++){ s[j]=string(&c); c++; if(j%10==0) m[s[j]]=true; else m[s[j]]=false; } map<string,bool>::iterator i; //削除処理 for(i=m.begin();i!=m.end();i++){ if(i->second){ m.erase(i); } }

  • mapによるkeyとvalueのinsertに失敗しております。

    STLのmapコンテナにて、 valueを取得したり、 keyとvalueを登録するソースを書いていました。 get(key)にあたって、 valの取得に失敗した際には、 mapコンテナ上のkey-valueデータと 同期されているMySQLより、 データを取得してきます。 MySQLよりkeyに対応するvalの取得が 完了したら、 そのkeyとvalをmapコンテナに insertしたいと思っています。 つきまして、 insertを行おうと、 「_container.insert(std::make_pair(key, val));」の一文を ソースに挿入したところ、 「型が違う!」という内容(?)のエラー文で コンパイル時に怒られてしまいました。 ただ、「どの様に直してごらん!」と エラー文が言っているのか、 今いち、意味を理解できないでいます。 このエラー情報的には、 どんな風の型の改善を求められているのでしょうか? 教えていただけるとありがたいです。 もし可能でしたら、pointBの 「_container.insert(std::make_pair(key, val));」の部分で、 MySQLから取得済みkeyとvalを、 pointAのkeyとvalに代入する方法も 教えていただけるとありがたいです。 どちらかでも、 アドバイスをいただけますとありがたいです。 どうぞ宜しくお願い致します。 -------------------------------------------------- template<typename KEY, typename VALUE> class hoge : public service_object<ipl<KEY, VALUE>> { virtual void put(key_type key, value_type val) { _container.insert(std::make_pair(key, val)); // pointA } virtual cc::fu<value_type> get(key_type key) { typename container_type::iterator iterator = _container.find(key); if (iterator != _container.end()) { return cc::fu<value_type>((*iterator).second); }else { //getにした場合MySQLよりkeyとvalueを取得完了できるので取得した。 /* MySQLより取得したkeyとvalをpointAのようにmapコンテナにinsertしたい。*/ _container.insert(std::make_pair(key, val)); //pointB  } } }; -------------------------------------------------- ■エラー文 error: conversion from std::pair<std::_Rb_tree_iterator<std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, boost::shared_ptr<csx::basic_message_cons<csx::basic_message<void, char> > > > >, bool>’ to non-scalar type ‘csrpc::future<boost::shared_ptr<csx::basic_message_cons<csx::basic_message<void, char> > > >’ requested

  • Javaのサーブレットについて(マルチスレッド)

    サーブレットについて質問です。 サーブレットは1インスタンス・複数スレッドという形態で、 サーブレットコンテナにより管理されていると思います。 では、このコンテナ内では、どのように1インスタンス・複数スレッドを 実現しているのでしょうか? 以下、自分なりに考えたプログラムです。 たぶん、このようにすれば、1インスタンス・複数スレッドになるのかと思うのですが。 どなたかご教授願いますでしょうか。 よろしくお願いいたします。 【1インスタンス・複数スレッドプログラム例】 public class TestThread extends Thread { public void run() { System.out.println("TestThread.run()"); } public static void main(String[] args) { Thread tt = new TestThread(); Thread th1 = new Thread(tt); Thread th2 = new Thread(tt); th1.start(); th2.start(); } }

  • DirectX 11のConsntanBuffer

    DirectX 11 ConsntanBufferの更新について マルチスレッドでConsntanBufferの更新を行うときにエラーが出てしまいます。 基本的な設計ですが、 1. メインのシーケンスを行うスレッド 2.DeviceContextに描画コマンドを詰むスレッド のスレッド2本構成です。 1から2へのスレッドへは仮想的な描画コマンドを発行し、 ダブルバッファリングを行い並列性を高めています。 # よくある方式だと思います。 HLSLで簡単なシェーダを作りポリゴンを表示することはできたのですが、 DirectXをDebugモードで実行すると以下のようなエラーが出てしまいました。 D3D11: CORRUPTION: ID3D11DeviceContext::Map: Two threads were found to be executing functions associated with the same Device at the same time. This will cause corruption of memory. Appropriate thread synchronization needs to occur external to the Direct3D API. 3516 and 5376 are the implicated thread ids. [ MISCELLANEOUS CORRUPTION #28: CORRUPTED_MULTITHREADING ] 内容はスレッド間で同じバッファに対してID3D11DeviceContext::Mapを実行しているため、 中身が破壊される可能性があるというものです。 先述の通り、基本的にDeviceContextを取り扱うのは2のスレッドです。 しかし、内容が動的に変更されるバッファについては 1のスレッドでID3D11DeviceContext::Mapを実行し、 取得したアドレスを直接書き換えるようにしています。 エラーではID3D11DeviceContext::Mapが2つのスレッドで実行されているというのですが、 初期化時は別として、通常のアップデート処理を行っている間は1のスレッドでしか使っていません。 書き込み先のバッファもダブルバッファ化しており、 またCPUAccess / USAGE / BIND / MAPのフラグも D3D11_CPU_ACCESS_WRITE / D3D11_USAGE_DYNAMIC / D3D11_BIND_CONSTANT_BUFFER / D3D11_MAP_WRITE_DISCARD と、動的バッファを使うときの標準的な組み合わせで使用しています。 いろいろとサンプルプログラムを見ているのですが、 出回っているのは大抵がシングルスレッドで作られており、 今回の件に関してはあまり参考になりませんでした。 プログラム中ID3D11DeviceContext::Mapを呼び出しているところは かなり限定できるため、おそらく間違いないありません。 いろいろ調べては見たのですがエラーが出てしまう原因が特定できずに困っています。 エラーの解決方法をご存知の方はいらっしゃいますでしょうか? ■補則 D3D11_MAP_WRITE_DISCARDはCPUとGPUの同期を制御するフラグですので、 CPUとCPUの競合がおきている今回の件とは別のはずです。 他にはID3D11DeviceContextのメソッド中の何かが 内部でID3D11DeviceContext::Mapを呼び出している可能性がありそうです。 2のスレッドで問題のバッファにアクセスしているメソッドは ID3D11DeviceContext::VSSetConstantBuffersぐらいです。 (これが内部でMapを呼び出しているとは思えませんが…)

  • 全パッケージの取得、全クラスの取得、全メソッドの取得

    やりたい事は、メインクラスより、同階層の全パッケージを取得(A)、 (A)より同階層の全クラスを取得(B)、 (B)より同階層の全メソッドを取得といったような事です。 例えば public class a { public static void main(String args[]) {  全パッケージの取得  全クラスの取得  全メソッドの取得 } } みたいな感じに。 試行錯誤したのですが、その処理を行う事の出来るメソッドかどうかも良く分からないし、 コンパイルエラーになるばかりで実現が出来ません。  ・メインクラスから同階層のパッケージを取得してパッケージ名を出力。  ・メインクラスからxパッケージ内の同階層のクラスを取得してクラス名を出力。  ・メインクラスからxパッケージにあるyクラス内のメソッドを取得してメソッド名を出力。 上記のようなめちゃくちゃシンプルなコードを挙げてご教示願います。

    • ベストアンサー
    • Java
  • C# HtmlDocumentでテキスト取得したい

    お世話になります。 HtmlDocumentで、タグの中のテキストのみを 取得したいのですが、どうもよく解りません。 例) <div id='a1'>あいうえお <span id='a2'>かきくけこ <span id='a3'>さしすせそ </span> たちつてと </span> なにぬねの </div> 上記のような例があった場合、idが『a1』のテキストを 取得しようと、メソッドのOuuerTextとInnerTextを呼び出すと、 『あいうえおかきくけこさしすせそたちつてとなにぬねの』と、 その中すべてが帰ってきてしまいます。しかも配列ではなく、 一つの文字列として。 a1で取得した場合、『あいうえお』と『なにぬねの』の 配列変数で取得したいのですが(つまり、ほかのタグで 囲まれているものは走査しないが、区切りとしては見る)、 メソッド一発でできないのでしょうか。 OuterTextとInnerTextの効果の違いもよくわかりません。 コツコツと手作業で行うしかないのでしょうか? よろしくお願いします。

  • ストアド。存在チェックをしてから登録したい。

    SQLServer2005環境です。 同じ構造のテーブルA、Bがあり、AのデータをBにコピーしたいと思っています。 Aのデータは最新のデータ、Bの中にあるのは古いデータなので、もしキーが かぶるレコードがあれば、Updateをかけ、なければInsertをするような仕組みに したいと思っています。 更に可能であれば、Aに存在しないデータがBにあった場合は、Deleteしたいです。 一度BをDeleteしてInsertすれば話が早いのですが、そうもいかず、UpdateとInsertを 交え、小出しに更新するような形にしたいのです。 2008であれば、Merge文という便利なものがあるのですが、2005では上のような 動作をストアドで実現するのは難しいでしょうか。 サンプルコードですとか、解説しているサイトなどがありましたら、教えていただけますと 大変助かります。 宜しくお願いします。

  • Javaで詳細なキー入力情報を受け取る方法を探しています。

    Javaで詳細なキー入力情報を受け取る方法を探しています。 現在友人とふたりでRPGゲームを制作しているのですが、入力処理で必要な機能が出てきました。キーボードからの入力です。 いま、私たちは複数の機能を求めています。 ・キーが押されている間常に真になるメソッド。 ・キーが押されている間、リピートのタイミングで真になるメソッド。 ・キーが押された瞬間だけ真になるメソッド。 ・キーボード入力は静的クラスRPG_Keyboardのメソッドを呼び出すことで取得できる。 ・キーボード入力はフレームごとにリフレッシュする。その際はRPG_Keyboardの更新用メソッドを呼び出す 手がかりだけでも良いので教えて頂ければありがたいです。

  • javaのRandomAccessSubListについて

    javaについて質問です。 RandomAccessSubListとはいったい なんでしょうか? RandomAccessSubListをSerializableで型変換しようとしてもエラーになってしまいます。 具体例として今やりたいことは 20件のデータのうち、10件のみ取得して更新処理をしたいのですが、10件のみ取得するというメソッドが業務フレームワークで提供されています。Listで取得するのですが、その際にListの中身がRandomAccessSubListが入っているのです。その為、Serializable化しようとしてもエラーになってしまいます。 わかりにくい説明で申し訳ありませんが、知りたいことはRandomAccessSubListとはなんなのかということです。Listとなにが違うのか、具体的な利用例ではどう使われるのか? ご教授お願い致します。

  • oracle sequence

    oracleのシーケンスでdual表からselect文のnextvalで取得したものをインサート したいのですが、ループ内で上記処理を複数回行ったときに、値が一回目以降 更新されずに困っています。 例) for (i=0;i < 5){ (1)セレクト文発行しシーケンスを取得。 (2)取得したシーケンスを変数にセット (3)インサート実行(主キーに取得したシーケンスをセット) } こんな感じで実行したときに、はじめはシーケンスが+1されますが、 それ以降シーケンスが増加しません。そのため、重複エラーが発生してしまいます。。。 どのように対処したらよいのかまったく見当がつきません。 大変申し訳ないのですが、ご教示いただきたくよろしくお願い申し上げます。

専門家に質問してみよう