私にはさっぱり分からないレベルになっていますが
専門知識が多すぎて質問者が口出しできる話では
なくなっていませんか?
皆様、それ程の知識があれば比較出来るサンプルコードなりを
提示すれば良いと思うのです。
質問内容から、質問されている方はスレッドやら排他制御に関する知識が
ある程度ある方だと判断しました。
ハードウエアよりの話になるとさすがに深い話になっていると思いますが、
クリティカルセクションで排他を掛けるというレベルであれば、
既に検討されていると考えています。
(実際に設計したという記述もありますし)
クリティカルセクションというキーワードも出ているわけですし、
Web上で検索をかければ、サンプルソースも見つけられると思いますよ。
皆さん、たくさんの回答ありがとうございます。
先週末から外出しがちで中々返事を書けず申し訳ありません。
詳細な事は書けませんが、今回のプログラムは厳しい性能(処理速度)を求められてい
ます。
このため、不必要な処理があれば1つでも減らしたいと思っております。
今までは、「念のため」や「とりあえず」と言う意図で処理を実装していたこともあり
ましたが、今回の件で不必要な処理は実装しないと言う考え方もあるのだと実感しまし
た。ただ、今回のケースの排他制御がCPUの動作などを含め、不必要かどうか判断できず
書き込みました。
また、動作保障の件ですが、特定のハードウェアに限定しても構いません。
何か良い意見があれば引き続き書込みお願いします。
> このため、不必要な処理があれば1つでも減らしたいと思っております。
事情は察しました。
であれば、結果として不要な処理を削除することも賛成です。
ただし...
その上で私の意見を述べておくと、やはり、排他処理はとりあえず実装してみる
方がいいと思います。
実装して動作確認が終わったら、コメントアウトしてしまうのです。
で、コメントアウトの理由もコメントにします。
「処理速度アップのため排他処理を省略しました。」
これで、未来に起きるであろう(特定のハードウェア以外での)不具合発生時に、
すみやかに対処することができます。
>詳細な事は書けませんが、今回のプログラムは厳しい性能(処理速度)を求められてい
>ます。
>このため、不必要な処理があれば1つでも減らしたいと思っております。
パフォーマンスが問題になっているのであれば
まずはInterlocked系APIを使う場合とロックなしの場合とで
どの程度差があるかを計測。
わずかなオーバーヘッドがどうしても気になるなら
排他なしにするのも一つの手でしょう。
私も仕様変更時のバグ混入や、実行環境変更時の暴走のリスクを考えると
オススメはできませんが・・・
>今回のケースの排他制御がCPUの動作などを含め、不必要かどうか判断できず
>書き込みました。
int変数一つだけであればメモリ操作での一貫性については問題ないと思います。
問題は環境によって読み書きの順が保障されないことですが
これも前回示したリンク先の内容を信じるなら
Windows + VC++2005以降のコンパイラであれば
volatileキーワードだけで保障されるのかな(?)
#書き込みスレッド1つだからそもそも要らない?
>また、動作保障の件ですが、特定のハードウェアに限定しても構いません。
よほど特殊な事情がない限りそういうことはしないので
実際に確認までしてくれる人はなかなかいないかも。
むしろpav777さんが調べて確認できたことをここに
フィードバックしてほしいです。
>今回のプログラムは厳しい性能(処理速度)を求められています。
どのぐらいですか?
スレッド中処理できる時間は約200mSです。
約200mSの処理が終了した後、スレッドを終了し約200mS間はOSに明け渡さなければ
いけません。
基本的な仕様ですから、マシンの性能によって変わるかも知れません。
リアルタイム性が必要となるならばそこのところを考慮しないとまずいと思います。
処理スピードも、μS以内を維持したいとなるとデバイスドライバーを作ることも
考えないとまずいと思います。
そういう言い方は正しくないと思うが・・・少なくとも誤解を招くと思う。
・スレッドを終了させるって文言がまずダメ
・200msec って話も必ずしも正しくない
・リアルタイム性って文言も「何に対する」って主語が無くて意味が不明
UI スレッドでは、各1つのメッセージに対する処理を可能な限り速く終わらせて
OSに処理時間を戻す必要がある、なら正確だけど
(処理時間を譲っているだけで、スレッドを終了させているわけではない)
(ユーザ操作に対するレスポンスを維持したいため)
ワーカースレッドでOSに処理を戻さないまま100%CPUを使い続けても
誰も文句言わないし問題ない。
(ユーザー操作に対するレスポンスは落ちるが計算処理のリアルタイム性はあがる)
んで、本題のほうは
・ int 1つ
・ Writer x1 + Reader xN
であるなら「結果論として」排他不要でおK。
・スレッドを終了させるって文言がまずダメ
そうですね注意します。
・200msec って話も必ずしも正しくない
・リアルタイム性って文言も「何に対する」って主語が無くて意味が不明
途中で終わってしまいました。。。。。。
> ・スレッドを終了させるって文言がまずダメ
そうですね注意します。
>・200msec って話も必ずしも正しくない
>・リアルタイム性って文言も「何に対する」って主語が無くて意味が不明
確かに200mSと決めたらまずいですね。
マシンの性能もOSも変わっているし、
ただ、
「絶えず連続でデータをやり取りすることが出来ない」。
ということをいいたかっただけです。
>UI スレッドでは、各1つのメッセージに対する処理を可能な限り速く終わらせて
>OSに処理時間を戻す必要がある、なら正確だけど
>(処理時間を譲っているだけで、スレッドを終了させているわけではない)
そうですね、「処理時間を譲っている。」が正しいです。
>(ユーザ操作に対するレスポンスを維持したいため)
処理よっては、OSの処理時間確保のため中断される場合があります。
スレッド優先順位を変更すればいいのかも知れませんが、
>今回のプログラムは厳しい性能(処理速度)を求められています。
という話だったので書きました。
> int変数一つだけであればメモリ操作での一貫性については問題ないと思います。
> 問題は環境によって読み書きの順が保障されないことですが
> これも前回示したリンク先の内容を信じるなら> Windows + VC++2005以降のコンパイラ
であれば
> volatileキーワードだけで保障されるのかな(?)
そのひとつの変数がそれだけで独立して使われるならvolatileのみで大丈夫でしょうね。
リンク先の
| x86 の CPU および x64 の CPU の場合でも、他の書き込みに対して
| 書き込みの順序が変更されたり、他の読み取りに対して読み取りの
| 順序が変更されたりすることはありませんが、読み取りの順序が
| 書き込みに対して変更されることはあります。
という書き込みから、そのひとつの変数が、他の変数への参照を制御するフラグと
して使われるようなら、メモリバリアをうまく使わないと問題ありそうです。
「ひとつのint型整数 (便宜的にxとします) については、ひとつの書き込みと
複数の読み込みが同時に行われるけど半端な状態にはならないから大丈夫。(ここまでは
OK)
他の変数はxがフラグとなってくれるから同期の問題は解決するね。」
と思ってしまうと痛い目に遭うんじゃないかな? と。
余談ながら、
http://www.linuxjournal.com/article/8211/
http://www.linuxjournal.com/article/8212/
で、何故こんなことが起こるのか、というのと、有名所のプロセッサ毎の挙動が
割と分かりやすく解説されています。(ただし英語)
Linux関連サイトの記事ではありますが、プロセッサ周りの話なので、Windows
であっても事情は同じですね。
実際に実測してどの程度の影響があるのかを確認した後の判断になるかと
思います。排他処理に関しては動作保障の観点から行くとあるべきというのが
私の考えです。但し、処理速度の要求上どうしても省かざるえないのであれば、
指定した環境であれば、原理的に大丈夫である事という条件をつけて
外すと思います。いずれにせよ、エイジングテストをしてもこの手の不具合を
必ず見つけると言うのは不可能ですし、そこから先は考え方一つだと思います。
うーん、
実際に測ってみてないんですが、排他処理にかかる時間って気になるものなので
しょうか。どうでしょうか?存知の方お願いします。
僕は、些細な時間だと思っています。
その時間さえ許されない処理とはどのようなことをやるかは不明ですが、
WINDOWS環境でも厳しいのでは?と思ってしまいますが、どうでしょうか?
僕が、速度的に気になるのはディスクに書き込むときですね。
「マップトファイル」や「CMemFile」等でメモリーに書込み、処理が終了した時点で
ディスクに書込むってのはどうでしょうか?
pav777さんもすでに考慮に入れているかもしれませんが、こういった観点から
もう一度振り返ってみるのも大切だと思います。
そんなに気になることは無いと思うけど頻度によるでしょ。
それとは関係ないけど面倒だよね。
抜けがあっては意味ないし、
全部一つのミューテックスで止めてたら効率悪そうだから工夫したり、
でもうっかりするとデッドロックになるし。
先に待ちに入ったのに後から待ちに入った方が
ミューテックス獲得するとかでなにかと後回しにされるスレッドがあるとしたら
どういうセオリーでプログラミングするのがいい方法なんだろう。
// XPやくあっどこあならそういう状況になりにくいんだろうな。
リンク先の内容から引用するとWindowsでのパフォーマンスの目安は
* MemoryBarrier: 20 ~ 90 サイクル
* InterlockedIncrement: 36 ~ 90 サイクル
* クリティカル セクションの獲得または解放 : 40 ~ 100 サイクル
* ミューテックスの獲得または解放 : 約 750 ~ 2500 サイクル
となっているようです。
名前なしミューテックスとクリティカルセクションは
クリティカル領域のロック用途であれば効果は同じなので
特に理由がない限りクリティカルセクションの方が
よく使われると思います。
また用途にもよりますがフラグやカウンタなどはInterlockedXxxが
適していることも多いです。
>先に待ちに入ったのに後から待ちに入った方が
>ミューテックス獲得するとかでなにかと後回しにされるスレッドがあるとしたら
>どういうセオリーでプログラミングするのがいい方法なんだろう。
クリティカル領域の期間が長いときは問題になることもありそうです。
今回の例ではアクセスが局所的すぎて不向きですが、場合によっては
.NET Framework の ReaderWriterLock クラスや ReaderWriterLockSlim クラス
のようなものも検討されると思います。
Windows Vista からはネイティブで slim reader/writer ロックのAPIがサポートされて
います。
http://msdn.microsoft.com/ja-jp/magazine/cc163405.aspx