• ベストアンサー

マルチスレッドと変数

マルチスレッドのプログラムを組んでいます。 そこで、複数のスレッドからアクセスする変数があるのですが、これの扱いについて解らないことがあります。 ・変数を複数のスレッドから書き換える場合は、予想していた結果と違うことになる。 ここまではいいのですが、 ・変数を複数のスレッドから、参照だけするのは問題ない。 ・変数を複数のスレッドから、参照し、書き換えるのはひとつのスレッドだけならば、問題はない。 (上の"変数"は全て、Lockをかけていない状態です。) という認識をもっているのですが、これは間違いなのでしょうか? 「参照だけならばLockはかけなくてよい」というのをどこかで読んだような覚えがあり、そのまま勝手に最後の推測をしています。 現状ではうまくいっているようなのですが、とても不安です。 もしくは、状況、環境、コーディングによって上の仮定は成立したり、成立しなかったりするのでしょうか?環境はC#ですが、もしどのような言語、環境であっても一般的に、同じような結果になるのなら、それも合わせてご教授お願いします。

  • qOat
  • お礼率80% (42/52)

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

  • ベストアンサー
  • rinkun
  • ベストアンサー率44% (706/1571)
回答No.4

ANo.3の補足の件。 long型(64ビット)だと、32ビットCPUでは一命令でアクセスできずに上位ワードと下位ワードの2回に分けてアクセスするため、その間に別スレッドからの書き換えが割り込むと拙いからです。 2ワードのアクセスの間に他スレッドからの書き換えが起きないことをロック以外の方法で保証できるなら読み込みロックは必要ありません。 なお、レジスタワード長が16ビット以下のCPUでは32ビット変数の一命令アクセスができないので、32ビット変数でも同様に複数スレッド間での排他処理が必要です。 # 16ビットCPUといってもレジスタワード長は32ビットのものも多いけど

qOat
質問者

お礼

丁寧な回答ありがとうございます。 とてもためになりました。

その他の回答 (3)

  • rinkun
  • ベストアンサー率44% (706/1571)
回答No.3

変数がint型のような単純な整数変数なら読み出しはロックなしで問題ありません。 しかし、long型(64ビット)やクラス型のオブジェクトだと、一回の処理で読み出しができないため、読み出し途中に書き換えられて異常な値を読む恐れがあります。 たとえば、マウスの座標(x,y)を読むことを考えましょう。始めの座標は(0,0)で、読み出しスレッドがx座標を読んでからy座標を読むまでに座標が(100,100)に書き換えられると、読み出しスレッドは書き換え前とも書き換え後とも違う座標(0,100)を読むことになります。 このように途中で別スレッドが割り込む可能性がある読み出しではロックが必要になります。

qOat
質問者

お礼

回答ありがとうございます。 そうなんですよね。単体のフィールドならば、問題ないと思うのですけど、複数あって意味のあるものだと、単に読んでしまうと、rinkunさんのおっしゃるようなことが起こりえますよね。 十分留意していきたいと思います。

qOat
質問者

補足

すいません。質問です。 クラスのインスタンスだと、フィールドが複数読む場合に問題があるのはわかるのですが、longでも問題になるのは、alignなどの問題のためでしょうか?それとも、他の問題なのでしょうか?

回答No.2

したい処理によります。 いつ他のスレッドに切り替わるかは、プログラム作成者には分かりません。だから、いつも最悪のタイミングを想定してください。 データを参照したあと・かつ・そのデータを処理する前に他のスレッドによって変数が書き換えられることが考えられますよね。 片方の進捗状況を確認するだけなどのゆるい関係ならそれでも構わないと思います。 が、二カ所以上を参照していて、それらが同じタイミングでのデータであるという前提でプログラム組んだりするとまずいことになります。 ロック取得してその変数に関わる処理をし終えてからロック解放、が原則です。

qOat
質問者

お礼

やはり、安全第一にやるべきですよね。。。。 これからは、原則に忠実にロック、解放をしようと思います。

回答No.1

基本的にはその通りです。 ただし本当に読むだけならよいのですが、普通は読んでその結果によって何かしますよね。この後で「何かする時」に書き換えられていない、という保証はできませんので、場合によっては読むだけでも、その状態が必要な区間書き換えられないように変数をlockすることもあります。

qOat
質問者

お礼

なるほど。 やはり、基本は「Lock」なのですね。 参考になります。 返答ありがとうございます。

関連するQ&A

  • マルチスレッドでのインスタンス変数

    http://itpro.nikkeibp.co.jp/article/COLUMN/20070820/279950/ このサイトに以下ような趣旨の記述があり、信じられない気持ちでいっぱいです。 「マルチスレッドのケース(たとえばサーブレットでは、)インスタンス変数はヒープ領域に 保持されるので、複数のスレッドからアクセスされるので情報が書き換えられる場合がある」 信じられないのは、インスタンス変数が書き換えられるということです。 サーブレットではインスタンス変数が共有されるのは理解していますが、 サーブレットから呼ばれるインスタンスで定義されているインスタンス変数も それに該当するのでしょうか。 それとも、サーブレット内だけの話で、サーブレットから呼ばれるインスタンスでは インスタンス変数は独立していると思ってよいでしょうか。 後者の認識ですが、こういう書き方をされると、サーブレットから呼ばれた先でも インスタンス変数が共有されると読めて、怖くて仕方ないです。

    • ベストアンサー
    • Java
  • マルチスレッドの疑問点と配列について

    こんばんわ。 VC++.NET2003を用いて、C言語プログラミングを行っています。以下に質問内容をまとめます。 1.現在、マルチスレッドを行っています。マルチスレッドの注意点として、 ・スレッドが複数同時に処理(現在2スレッド)され、それぞれのスレッドで同一のグローバル変数をアクセスする。 ・各スレッドで使用しているスタティック変数はプロセスとして1つの領域に確保される。 と記述されていました。 現在、2スレッド動かしているのですが、2スレッド共通で使用したい変数がある場合は、グローバル変数として宣言してよいのでしょうか? スタティック変数というのは、 static int i を指すのでしょうか・・・・初心者的発言で申し訳ありません。 次にもう一つ質問させていただきます。 配列を整数型で10000要素、静的に用意します。 これを、memset関数ですべての番地に0を初期値として入れておきます。 たとえば、9000という数字があった場合、9000番に整数値9000を格納する。また、56では56番に56を格納する。 そして、最終的に10000要素を走査し0の場所をカウントする。 ということは可能でしょうか?もしよろしければ、サンプルを教えていただきたいと思っています。 よろしくお願い致します。

  • マルチスレッド化。

    今とても大きな配列を使用し、長時間処理をするプログラムを組んでいます。元々処理時間に1時間を要するプログラムを2分で処理を完了するまでに仕上げました。 しかし、探究心はおさまらずもう少し高速化に挑みたいと考えています。 過去に「猫でもわかる」のSDK第1章と2章を学び、マルチスレッドのプログラムをSDKで組んだことがあります。それを利用してマルチスレッド化を実現したいと考えています。 言語はCでVisualStudio2005を使用しています。 *疑問1   SDKの場合WinMain関数とプロシージャからの実行で_beginthread関数を記述すれば処理が開始されます。 Cでもmain関数内に記述すれば、SDKと同様に処理できるのでしょうか? *疑問2 _beginthread関数の引数に関してです。 第1引数にvoid型のスレッド関数、第2引数に0?、そして第3引数にはスレッド関数に渡すデータの引数を記述すると把握しているのですが、渡したいデータは複数あり、***型と**型、それに変数を数個とスレッド関数に渡したいデータだらけなのですが、どのように記述すればよいでしょう? *疑問3 2つのスレッドを作成しようと考えていますが、その2つのスレッドで1つの大きな配列を共有して処理したいと考えています。 そのため、スレッド間の同期が必要になるわけですが同期の種類にもクリティカルセクションやミューテックス、イベントと豊富でどれを使用すれば良いのか迷ってしまいます。厳密に同期を取り処理をするにはイベントが一番良いと考えています。 これらの疑問に答えられる方はアドバイスをよろしくお願いします。

  • マルチスレッドの同期方法

     マルチスレッドで以下のような内容のプログラムを組みたいのですが、当方マルチスレッド超初心者で、ミューテックス、セマフォの基本的な使用方法は習得したつもりですが、この問題を解決する方法が見当もつきません。解決方法をご存知の方がいらっしゃいましたら、ご教授お願いします。  スレッドは全部で6本あります。そのうち、1本は初期状態では、停止しています。他のスレッド5本は、初期状態で動作を始めています。この5本のスレッドはそれぞれ決められたポイントで、何らかの方法で、一時停止をさせます。この5本のスレッドすべてがそれぞれのポイントで停止した時点で、初期状態で停止していた1本のスレッドが動き出し、今度は、このスレッドを決められたポイントに来た時点で、停止させます。停止が確認できたら、止めていた5本のスレッドを一挙に稼動させます。あとはこれの繰り返しです。  環境はWinXp, VC2005 です。

  • 非同期プログラミングは必ずマルチスレッド?

    非同期プログラミングは必ずマルチスレッドプログラミングになりますか? ここでいう非同期プログラミングとは、 何かのメソッドを実行してその処理(処理Aとする)の結果を待たずに次の処理Bを実行できて、処理Aが終わったらコールバックやデリゲートで、あらかじめ決められたメソッド(finishとする)が呼ばれるといったものです。 処理Aを実行するメソッドを呼ぶ ↓ すぐに処理Bを実行開始(このときバックグラウンドで処理Aが走っている) ↓ 処理Aが終了したのでfinishメソッドが実行される 例えば、Objective-CのNSURLConnectionで非同期通信するときのようなやつです。 こういった非同期プログラミングは、必ずマルチスレッドを使うことになりますか? 普通、別スレッドで処理させるときはスレッド用のライブラリを使うなどして明示的にマルチスレッドプログラミングをしますが、上のように非同期のメソッドを使うと、その裏で自動的に別のスレッドが動くのでしょうか。 それとも、単一スレッドのみで、非同期プログラミングできるでしょうか。 なお、特殊な言語やOSによっては、いくらでも可能性があると思いますので、 メジャーな環境(Windowsや、スマホ) のみに限定してお願いします。言語で言うと、C、C++、Objective-C、Javaあたり。 また、上の「処理A」が終わったとき、メソッド「finish」が呼ばれるとすると、 処理Bの実行中にどのようなタイミングでfinishが呼ばれるのでしょうか。 処理Bはどのような形でfinishに切り替わるのでしょうか。いきなりfinishに処理を奪い取られるのでしょうか

  • マルチスレッド環境での配列使用について

    現在、C++を利用してマルチスレッド環境の開発を行っています。 マルチスレッドで排他的に変数を扱う場合、クリティカルセクションや ミューテックスを使用することで、排他制御をおこなうことができますが、 このように、配列の要素ごとに排他制御を行うことは可能でしょうか? たとえば、 int ary[10]; のような配列があれば、a[0]~a[9]まで要素をそれぞれ排他制御によって データの矛盾を避けたいと考えています。 パフォーマンスの関係上、できるだけ、配列全体をロックするのは避けたいと 思っています。 どうぞよろしくお願いします。

  • マルチスレッドでブレイクポイントするとフリーズする

    C++/CLI .Net2008 windowsフォームアプリケーション 二つのスレッドが同時に動いているマルチスレッドプログラムを作成しています。 デバッグでブレイクポイントを張って途中で止めたいのですが、止めてすぐもしくはF10で2,3行進めるとフリーズしてアプリが動かなくなってしまいます。他のoutlook等も動かせず、タスクマネージャも開かないため、画面下のウィンドウを右クリック、閉じるを5~10分くらいかけて行って終了させています。たまにVisualStudio自体もフリーズして落ちることがあります。 ブレイクポイントで止めなければフリーズはしません。 プログラムの構成としては、 片方は外部装置からリアルタイムでデータを受信し、判別した結果を出力するスレッドと、その判別結果を元に状態を遷移させるスレッドです。 また、状態によってはタイマーを設けている箇所があり、タイマー処理もスレッドで行っています。 ブレイク張らずに実行した時におかしい動作をしている箇所があるので1行ずつ見たいのですが、マルチスレッド環境ではフリーズするものなのでしょうか?

  • マルチスレッドプログラミングの利点について

    はじめまして。 質問があります。 現在マルチスレッドプログラミングについて学習しているのですが、 学習を進めていくうちにある疑問が思いつきました。それは、 マルチスレッドで実装した方がよい場合とシングルスレッドで実装 した方がよい場合の区別がよくわからないということです。マルチスレ ッドで実装する利点は、例えば、応答性を向上させるとか、 入出力操作が関わっているときにCPUの空き時間を利用して別スレッド で処理を行わせることによってスループットを向上させることぐらいしか思いつきません。また、CPUが1個しかない環境では、 CPUをフル活動するようなプログラムでは、下手にマルチスレッドで 実装するよりもシングルスレッドで実装したほうが排他制御しない 分だけ処理スピードは上であると思っているのですが、間違いでしょうか?マルチスレッドで実装した場合の利点は上述したこと以外にも 何かあるのでしょうか?ご教授お願いします。

    • ベストアンサー
    • Java
  • DirectX LPDIRECT3DDEVICE9のマルチスレッドでの使用について

    お世話になっております。 さて、現在DirectX 9.0cを用いたゲームを製作しています。 このゲーム内で、いわゆるNowLoadingの画面を作成しているのですが、ここで気になることがあります。 ここでのNowLoadingの要件は、"描画とは別にスレッドを作成し、そのスレッドでロード処理を行う"ことです。 そこで、ドキュメント(古いDirectXの日本語ドキュメント)でマルチスレッドについて言及している箇所を検索してみると、CreateDeviceの引数にD3DCREATE_MULTITHREADEDを入れると、マルチスレッドに対応すると書いてあります。しかし、同時にパフォーマンスを下げるとの記述もあります。 しかし、D3DXCreateTextureFromFileなどD3DXCreate**系の関数が、LPDIRECT3DDEVICE9に対して参照だけを行い、BeginSceneなど描画に関する関数の挙動には(LPDIRECT3DDEVICE9に同時にアクセスしたとしても)、なんら影響がないならば、わざわざこのD3DCREATE_MULTITHREADEDフラグを使いたくありません。 そこで、サンプルを作成してみました。 http://briefcase.yahoo.co.jp/bc/multithreaddevicesrc/lst?&.dir=/&.src=bc&.view=l このサンプルは、上記の処理をD3DCREATE_MULTITHREADEDフラグをいれず、そのまま行っているもので、テクスチャを別スレッドで、ひたすらロードと、解放を行っています。これを実行した結果、特に問題ない(強制終了などしない)ように見えました。 この結果は、"たまたま動いている"だけなのでしょうか、それとも"必然的"なもので、別段行ってもいいものなのでしょうか?もしくは、状況による(SetRenderStateなどの使い方による、など)ものなのでしょうか? ご教授よろしくお願いします。 環境は、DirectX9.0c (2008March)、XP sp3 になります。

  • マルチスレッドへの対応について

    もう出て結構経ちますがグアドコアでましたね しかしCPU(以下コアと同義)が幾つあろうとも 最適なロードバランシングやソフトのマルチスレッド対応が一般化しないと 宝の持ち腐れになると聞いたことがあります インテルとしては グアドコアの性能発揮奈何に社運が掛かってくる と思われますが 一方で以前よりHyper thresd等は存在しており 最適なロードバランシングやソフトのマルチスレッド対応等の マルチCPU(以降マルチと称す)へのアプリケーション対応に対する潜在的なニーズはあったと思われます しかし現状として 一部の高額ソフトを除いて マルチ対応度は低いままのように 私は感じられてなりません そこで質問なのですが 質問1 最適なロードバランシングを実現する上で グアドコアはマルチスレッド非対応アプリケーションに対する 有効な手法を取り入れているのでしょうか? 質問2 やはり最適なロードバランシングを実現するには アプリケーションのマルチスレッド化が一番重要かと思うのですが インテルは今後マルチスレッド対応普及に向けて何か策を講じてくると思われますか? 質問3 インテルは単一CPU(コア)に対し希望を見いだせていない… ような報道を見かけたのですが 今後ロースペックのマルチCPU化を狙ってくるでしょうか? 質問4 趣味程度のソフト開発者などが 得に何の意識をもせず開発を行っても マルチスレッド対応ソフトがほぼ生成される程に 今後アプリケーションのマルチスレッド化は一般化し 標準化していくのでしょうか? 以上、私自身Pen3 2CPU構成を使っているので マルチへの対応度の向上は 頭を抱えさせられていた問題であると共に 注視せざるを得ないものでした。 ので、 ご意見を伺いたくスレッドを立ててみました 皆様宜しくお願い致します

専門家に質問してみよう