>>993 > lock-freeをある程度かじれば分かるが、要素数もatomicじゃなくていいよ
> スレッド状態は特権リング内の管理だろうから内部の挙動はシラネ
> ユーザーレベルで言うなら、lock-free queueをスピン&スリープで待機するなら
> スレッド状態も持つ必要なし
spinlock なら普通はスリープじゃなくて再スケジュー
ルじゃないだろか。まぁいいけどさ。
でか、spinlock 使う位なら俺にとってはキュー操作と
一緒にやる作業の大きさで mutex にするか spinlock
にするかってだけの話になって、キュー自体にはやっぱ
り排他責務なんか持たせないなぁ…。
あ、「キューに特化するとキューの特性に沿ったとても
効率の良い spinlock 的な何かがある」ってこと?
それとも、生産者が一つ生産してキューに生産物を入れ
る度に上限数まで消費者スレッドを起こして、とかいう
生産時間<<消費時間な場合に使うわけ? 確かにこの場合
は有効そうだけど。
スレ立て乙
mutexとspinlockの使い分けが全く要らないと思ってるなら、単に畑違いだと思うよ…
>>3 普通にlock-free queueを全く分かってなくね?
アトミック操作も要らないタイプすら作れるんだが、何でキュー自体に排他機能とか
変な話になってるんだ。
>>6 >アトミック操作も要らないタイプすら作れるんだが
詳しく
ぶっちゃけ、新スレまで引っ張るなよと言いたい。 低水準の要る要らないなんて、まともに終わったためしが無い。
>>7 lock-free queueはメモリバリアだけで十分作れるよ。前提条件によるけど。
CAS無しでやる話とかは前スレで出てたな
>>9 大変失礼、そう言うことですね。
勘違いしておりました。
lock-free queueでスピンってspin-waitであってspin-lockじゃなくね そもそも"lock-free"の意味的にlockする訳が
lock-free queueって、計算処理は非常に重いけど、スレッドモデルとしては
比較的単純なケース(マスタ-スレーブモデル)に利用されるものなのかな?
たとえば動画エンコ/3Dレンダ/科学計算といった応用のように、
親スレッドが複数の子スレッドを生成し、各子スレッドが計算処理を実行し、
結果をlock-free queueに追加していく。親スレッドはjoinですべての計算の
終了を待ち、joinから抜けたらqueueから順に計算結果を取り出す...みたいな。
このモデルだと、スレッド間の同期なんて考える必要はまったく無い。
>>3 の生産者-消費者モデルというのは、スレッド間同期の代表的な題材だから、
lock-free queueの話題とするのは、そもそも畑違いであると。
lock-free queueについては分かっていないので、有識者の指摘たのむ。
14 :
13 :2009/09/22(火) 01:44:44
(
>>13 の続き)
あるいは、
>>13 の応用ならリアルタイム性は要求されず、しかも
計算処理が(親スレッドの処理よりも相対的に)重いという前提があるから、
親スレッドは全子スレッド群の終了を(joinで)待ってから再開しなくても、
pollingで定期的にqueueから計算結果を取り出し、ゆっくりと
計算処理の進捗状況に合わせて出力(画面表示)していく方法だってある。
これもスレッド間の同期は考えなくてもいい。
なにかlock-free queueの利用イメージが見えたような気がするのは漏れだけ?
lock-free queue専門家からすれば「何を今更、そんなの常識」な話なのかな?
そういう使い方はたぶん一般的だろうと思う 一対一の一方通行queueを双方向に張って適当にポーリングして同期っぽいことも やれるし ただ、汎用性をちょっと変えただけで実装が変わるから、結局バスロックするような queueもあるだろうし、その辺ひっくるめてまとめて語るほどの経験は無いし
>>6 > 普通にlock-free queueを全く分かってなくね?
> アトミック操作も要らないタイプすら作れる
lock-free と wait-free を混同してね?
wait-freeが作れるならlock-freeでもあるからいいんじゃね?
>>6 是非作り方を教えてくれ。
アトミック操作もいらないなんて、君にとっては些細なことでも俺にとっては非常に大きな一歩なんだ。
どう見ても「本当は知らないんだろ?」と煽ってるようにしか見えないが… ちょっと真面目に考えてみろよ。書き手が単数の場合、アトミック操作は要るか? メモリバリアだけで書けるだろ。wait-freeじゃなくてlock-freeなんだから、準備 できてない間は待ってて貰っていいんだぞ。 複数の書き手を作るには、ハブのようなスレッドを作ってスター型トポロジーに すればいい。 つーか、コードを全部示さないと信用できないってんなら、信用されなくていい。 勝手に妄想家とでも思っててくれ。いちいち何から何まで言うつもりは無い。
顔真っ赤にすんなよ^^;
妄想乙
>>19 > ちょっと真面目に考えてみろよ。書き手が単数の場合、アトミック操作は要るか?
ん、「書き手が単数」ってのはどこからわいてきた話だ?
こういうのは設計・実装に大きく影響する話なんだから、
勝手に仮定されると議論が成り立たないと思うぞ。
というか、読み手と書き手がそれぞれ一つずつって前提が置けるのであれば、
CASなしでwait-freeなキューを作るのは難しくないし。
23 :
13 :2009/09/22(火) 20:46:03
>>14 レスありがとうございます。まずは、マスタ-スレーブモデルは一般的だろうと
いうことで、lock-free queue勉強の一歩を進めることができます。
あと、
>>14 のポーリング方式はスレッドプールモデルにも適用できますね。
スレッドプールとポーリングの組み合わせたキーワードで考えると、
更にlock-free queueの応用範囲が広がる気がします。
>>22 書き手が複数の場合どうするかも書いてあるだろ…
>>24 「ハブのようなスレッドを作ってスター型トポロジー」みたいな構造は
もはや「書き手複数で使えるキュー」とは言えないと俺は思うがねえ…
「ハブのようなスレッド」がそれぞれの書き手と繋がったキューを
順次ぐるぐるとチェックして回るんだろ?
それだけでCPUの1コアの使用率が100%になっちまうじゃねえか。
で、読み手が複数の場合はどのように対処するんで?
>>25 横だけど「ハブのようなスレッド」が渡して回るんじゃないの?
ほとんど(まったく?)lock-freeの利点が活きていないけど。
前スレからの元々の流れ忘れてる奴多くね? 俺も忘れたけど
まとめると、 書き手がひとつならアトミック不要、複数ならアトミック必要ですね。 読み手も同様
>>27 そんな君たちに僕の質問を再度コピペしておこう
| メモリとかキャッシュとかレジスターとかバスとかマルチコア/プロセッサーが絡むと
| どうなっているのかよくわからないからいつもmutex頼みです
| これらのHW関連とマルチスレッドについて詳しく知りたい場合のよい方法を教えてください
アセンブラでアトミック命令使ってみることをお勧めするであります。
31 :
デフォルトの名無しさん :2009/09/22(火) 21:55:29
>>26 > 横だけど「ハブのようなスレッド」が渡して回るんじゃないの?
キューだよ? FIFOだよ?
2つの読み手R1とR2がいて、R1はガリガリ計算中、
R2がキューから次の要素が来るのを待っているって状態なら、
次の要素はR2に渡さないといけないんだよ?
32 :
デフォルトの名無しさん :2009/09/22(火) 21:59:00
もしかして、lock-free, wait-freeの "wait" を sleep()とかyield()とかのことだと勘違いしている奴がいるんじゃないか?
と、このような有様ですので、lock-freeのライブラリなんかそうそう出回らないって訳です
www 俺以外全員馬鹿wwwww wwwwwwwwwwwwwwwww
>>32 lock-free queueとは、スレッド間で共有するキューがあっても、
そのアクセスに「lock操作そのものが不要(free)」なキューである。
これは分かる。
では、wait-free queueとは、スレッド間で共有するキューがあり、
たとえそのキューが空であっても「wait操作そのものが不要(free)」な
キューである。
うーみゅ、どうやって実装しているんだ?それとも何か勘違いしてる?
分かんねーーーヨ....orz
lock-freeはロック(mutexとか)がかからないけどCASなど無限時間の可能性がある。 wait-freeはロックがかからないし、一定時間で完了する。 でいいのかな?
>>36 > lock-freeはロック(mutexとか)がかからないけどCASなど無限時間の可能性がある。
CASで失敗したときは操作を繰り返す、ってのは lock-free なの?
だとしたら、スピンロックは lock-free ってことになるよね?
>>38 ロック変数をspinlockするのなら、それはlock-freeとは言えない
>>35 キューが空ならnullを返したり例外を投げたりすればいい。
たとえばJavaでは、要素が空のときにnullを返したりする Queue と、
要素が空のときに新たな要素が来るまで待機する操作がある BlockingQueue とが、
ちゃんと区別されている。
で、Queueにはwait-freeな実装クラス ConcurrentLinkedQueue があるけど、
BlockingQueueの実装クラスである LinkedBlockingQueue や ArrayBlockingQueue とかは
wait-freeでもlock-freeでもない。
で、君が欲しいのは Queue なの? BlockingQueueなの?
>>39 ロック変数をCASで変更しようとして失敗したらリトライってのはlock-freeではない。
リンクリストのポインタ変数とかをCASで変更しようとして失敗したらリトライってのはlock-freeである。
ってこと?
43 :
35 :2009/09/23(水) 06:49:21
>>40 レスありがトン。詳しい解説は、とても助かる。
欲しいのは、待機が可能なwait-free queueの実装クラスです。
この場合には、ConcurrentLinkedQueueでキューを生成し、
nullあるいは例外発生であればスレッドを(たとえばwait操作で)待機させるよう
アプリケーション側で実装することになるのでしょうか?
スレッドを待機させる方法はwait操作以外にもいろいろあるから、
どの方法を選ぶかはアプリケーションにまかせる、という考え方になります。
wait-free queueの意味が「wait操作そのものが不要なキュー」(
>>35 )ではなく、
「wait操作を実装していないキュー」の意味に思えてきました。
こんな感じで合っていますか?
LinkedListを使ってキューを作るならCASを使うのでlock-freeだがwait-freeにならない。 もし読み手をwaitでブロックさせるなら文字通りlock-freeでもwait-freeにもならない。 その場合、書き手はブロックした読み手を起こすためにカーネルの世話になるのでlockが発生するかもしれない。
>>43 > 欲しいのは、待機が可能なwait-free queueの実装クラスです。
「待機が可能な」ってことは BlockingQueue が欲しいってことだね。
BlockingQueueの実装方法は2つ。
・待機しないQueueを用意し、要素が空だったらスピンしまくる。
・「キューが空でない」という条件変数を用いたモニタ同期を組み込む。
前者は明らかにCPUの無駄遣い。
後者はlock-freeでもwait-freeでもない。
てことで、>40にも書いたようにJavaのBlockingQueueの実装クラスが
wait-freeでもlock-freeでもないのは、手抜きしているわけではなく
そのように実装するのが不可能だからだ。
> wait-free queueの意味が「wait操作そのものが不要なキュー」(
>>35 )ではなく、
> 「wait操作を実装していないキュー」の意味に思えてきました。
だからそれは "wait-free" って言葉の意味を誤解してるって。
"wait-free" の wait とは、モニタ同期のwait()操作とかとは別物。
もちろん、sleep()とかyield()でもない。
連結リスト使うくらいなら別にmutexでも、と思いかけたが、mutexは格段に重いから そうも言えないか
>>47 > mutexは格段に重いから
Win32のmutexが無駄に重いだけ。
最近のOSが用意しているmutexなら、競合がない場合のコストは
ロックとアンロックそれぞれで高々CAS一回分程度。
なら連結リストよりmutexの方がいい場面は多そうだな、Windows以外は
Win32のmutexはプロセスレベルじゃなくてシステムレベル? で排他してるから重いのはしょうがないかと・・
>>50 ですな。
というか、一般的に言う "mutex" に相当するものを、
Win32では "Critical Section" と呼んでいるから
混乱を招いているだけなんだけど。
W32はCSもMutexも両方Mutexで特性が違うと考えるのが自然
プロセスレベルで排他するからじゃなくて、 カーネルオブジェクトなのが原因なんじゃね?
目的がそうだからしょうがない
55 :
35 :2009/09/23(水) 13:27:30
>>45 >てことで、>40にも書いたようにJavaのBlockingQueueの実装クラスが
>wait-freeでもlock-freeでもないのは、手抜きしているわけではなく
>そのように実装するのが不可能だからだ。
明解な説明です。理解できました。
>だからそれは "wait-free" って言葉の意味を誤解してるって。
>"wait-free" の wait とは、モニタ同期のwait()操作とかとは別物。
そのモニタ同期のwaiti()操作をイメージしていました。間違っていたんですね。
でわ、wait-freeの意味は、単純に「待ちが発生しない」へ改めます。
となると、lock-freeの意味も「待ちが発生する」に変わります。
ただし、どちらも「lock操作は不要」という特徴は共通している、と。
これでスッキリしました。
実は
>>13 ,14,23のカキコ主だったのですが、lock-freeでは生産者-消費者モデルを
実現できない(畑違いである)ことが分かったので、次はwait-freeをと考えていましたが、
それも同様に誤解であることが理解できました。lock-free/wait-freeはスレッド間同期を
実現するプリミティブではない。それを実現するには、(lock操作を伴う)mutexや
モニタ同期(signal/wait)などを導入する必要がある、と。
lock-free/wait-freeの使い方について、ここ数日で急速にイメージが掴めてきた感覚です。
たいへんありがとうございました。>>all(特に
>>15 ,32,40,45)
後は、Javaだけでなく、C/C++でも利用できる一般的なlock-free/wait-freeの実装技法が
確立し、標準ライブラリとして仕様化されることを願っています。
え lock-free queueは同期にも使えるよね?
57 :
35 :2009/09/23(水) 14:30:47
>>56 lock-free queueは「待ちが発生する」キューなので、スレッド間同期に
利用できるように見えるのですが、実際にはスピンによる実装なので、
「一般的な」アプリケーションでは利用できないと考えました。
言い換えると、lock-free queueだけで(mutexやモニタを一切使わずに)
「一般的な」アプリケーションを開発することは、現実的ではないという判断です。
もちろん、スピンが許されるケースや、mutexなどのオーバヘッドさえも
問題視される環境下では、lock-free queueを使わざるをえないケースも
存在していることは承知しています。あるいは、パフォーマンスクリティカルな
部分だけをlock-free queueで同期させ、残る大半ではmutexを使う設計も
あるでしょう。論理的にlock-free queueが同期に利用できないと
考えているわけではありません。
58 :
35 :2009/09/23(水) 14:39:25
(
>>57 に追記)
>>57 の「一般的なアプリケーション」というのは、
生産者-消費者モデルで設計された、言い換えるとスレッド間同期が
前提となるマルチスレッドアプリケーションのことを指します。
たとえば
>>13 ,14のアプリケーションではスレッド間同期が
必要ありませんから、lock-free queueを使用することができます。
(もちろんwait-free queueも使用できます。)
CASとスピンは違うよ。スピンはロック解除待ちのループ。CASは更新中に割り込まれた場合のリトライ。 lock-freeの待ち時間は、よっぽどの酷い競合が起きたときに発生するにすぎない。一般的なアプリでは問題にならない。 そのような競合が起きるのは設計が悪いと思われる。
>>59 > スピンはロック解除待ちのループ。CASは更新中に割り込まれた場合のリトライ。
スピンロックは観察対象がロックオブジェクトで、CAS
は操作対象そのもの。
スピンロックは失敗時にはクリティカル領域に居る競合
相手の処理を促進する意味もあって普通ディスパッチす
ると思う(悪くすると飢餓状態に陥る)けど、CAS は領
域がそもそも小さいのですぐにリトライして ok ってこと?
相当限定的な使い方しか出来ない気がするなぁ…。「ス
レッドの状態を気にしなくて良い」んじゃなくて、気に
できないんじゃないの?
>>60 boostのshared_ptrもlock-freeで実装されていなかったっけ?
ヘッダ見ると幸せになれるかもね
スピン(に限らず)ロックは、ロックされていたら解放されるまでただ待つしかない ロック保持者が何か処理に手間取って (ページングとか、割り込みとかで) 時間を取られたら、 それに引きずられて後続が全部渋滞してしまう lock freeは、相手がすでに処理に入ってても我関せずで自分も処理に入ってしまい、 相手が何か手間取ってたら自分の方が先にCASを勝ち取り、次の処理に進めるというのが強み 負けた方は残念ながら最初からやり直し、今までやったことが無駄になるが、 今戦ってた相手はもう去ったし、次はたぶん成功するんじゃね? 次々に相手が現れていつまでも負け続けるようなひどい競合状態なら、普通のロックの方が良いらしい 負けたら同じ処理をもう一度やり直さないといけないという無駄がどうしてもあるし
>>63 そういうlock-freeもあるけど、単純にアトミックアクセスだけで済ます場合もlockが
無いならlock-freeって呼ぶし(boost::shared_ptrとかがまさにそれ)、その場合は
lock-freeと言ってもバスロックを使ったりしてるからややこしいんだが、要するに、
何があってもデッドロックしないアルゴリズムならlock-free、ということだと思って
いるんだが
デッドロックはまたややこしい話になると思うから置いとくとして そういうのはやっぱりwait freeに分類すべきじゃないかな wait freeもlock freeの一種といえばそうなんだけど
lock-free : ロックせずにアクセスできる wait-free : lock-freeの条件を満たしており定数時間で処理が完了する事が保証される だけでそれ以外の要素は各実装による・・・じゃねーの
まぁ
>>63 と全然違う仕組みのlock-freeも色々あるよってことで
> 何があってもデッドロックしないアルゴリズムならlock-free 俺はこれが一番合点がいった。(dead)lock-free なわけ ね。 …しかし「たまたま動いてたプログラムがより堅実に動 くようになります」っていうのはかなり微妙なメリット な気もする(w
69 :
35 :2009/09/23(水) 23:21:08
>>59 CASとスピンとで内部の実装方法が異なるのは分かります。
# その意味では、
>>57 は以下のように訂正したほうがよいかもしれませんね。
#
# X:利用できるように見えるのですが、実際にはスピンによる実装なので、
# O:利用できるように見えるのですが、実際にはCASやスピンによる実装なので、
#
# X:もちろん、スピンが許されるケースや、
# O:もちろん、CASやスピンが許されるケースや、
ただ、
>>3 が指摘した生産者-消費者モデルで生産時間<<消費時間な場合を除き、
言い換えると生産時間>消費時間な場合、大半の状態でキューは空(から)のままです。
その場合、(キューを読み出す側の)消費者スレッドは、どのようにして待てば
よいのでしょうか?CPUを無駄にせず、いかにリトライをループさせるのでしょうか?
たとえば一般的なアプリケーションのキー入力「待ち」はCASやスピンで実装できますか?
実は、生産者-消費者モデルに関する同じような疑問は
>>3 だけでなく、前スレでも
たびたびカキコされていたのですが、レスがないか、あっても消費者スレッドを
待たせる方法に関する説明が無く、ずっと考え込んでいました。それが、
>>45 のレスで
クリアになったので、生産者-消費者モデル実現の前提となるスレッド間の「同期」に
ついては、lock-free/wait-freeは使えないと判断できました。
もちろん生産者-消費者モデルであっても、スレッド間の共有キューへの「排他(競合対策)」
については、lock-free/wait-freeを使用できます。一時的な待ちへの対応ですから。
スレッド間の「同期」と「排他」を意識的に区別して使い分けていることに注意してください。
適当にスリープに落とせばいいんじゃ? カーネルにスケジューリングを任せるより効率は若干落ちるが、高負荷時を見れば lock-freeの恩恵が受けられるから悪くないかと。 スレッド間通信がボトルネックの外にあるなら、好きな方法でいいと思われ。
すみません初歩的な質問で申し訳ないのですが,mutexで排他制御された場合、例えば mutexlock(); A[0] = 0; mutexunlock(); の様な場合、スレッドAはA[0]をアクセスして、スレッドBはA[100]をアクセスするとします。 その場合、スレッドBはスレッドAの処理が終わるまで配列Aにアクセスできないのでしょうか?
「の様な場合」なんていう他人に通じない省略しないで、 スレッドBの処理も書けばいいのに
>>71 //mutexlock();
A[100] = ~0;
//mutexunlock();
:b
>>71 です。
しょうもない質問をしてすみません。mutexでロックをかけた場合、配列にアクセスする場合はその間配列全体がアクセス禁止になるのか、
それともその一部のみ(例えばキャッシュライン分)がアクセス禁止になるのかを知りたかったのです。
アクセスできないとなると、 int D[10000]位確保されていたとして、
int *A,*B,*C;
A = &D[0];
B = &D[1000];
C = &D[2400];
のようにポインタでAの場所を指して、
スレッドA: D[0]〜D[1199]の内容を書き換え、スレッドB:D[1200]〜D[2399]の内容を書き換え、スレッドC:D[2400]〜D[3599]の内容を書き換え、
オーバーラップする領域はまずAの処理を優先するため、その領域を保護するためにmutexでロックをかけている間、
BはAの処理が終わるのを待たなければならないのは分かるのですが、CもAの処理が終わるまで待たなければならないのでしょうか?
Thread A:
for(i=0;i<1200;i++){
mutexlock(mu);
A[i]=100;
mutec_unlock(mu);
}
Thread B:
for(i=0;i<1200;i++){
B[i]=200;
}
Thread C::
for(i=0;i<1200;i++){
C[i]=300;
}
>>61 > 相当限定的な使い方しか出来ない気がするなぁ…。
> 「スレッドの状態を気にしなくて良い」んじゃなくて、
> 気にできないんじゃないの?
これ書いたの俺だけど、malloc() の内部処理辺りには
使えそうだと思った。それと類似して C++ の new() を
オーバーライドしといて予め準備しといたメモリプール
から取ってくるとかいうよくある奴。
例としてはそんなのでいいだろか? > 例を要求してた人
>>75 その例の場合は素通り
配列が自動的にアクセス禁止になるわけではない
ThreadBもThreadCもmutexをロックしてどこからどこまで保護するのか明確にしなければならない
>>77 ロックする範囲が限定されていれば、
他のスレッドは進行を妨げられずに処理できるのですね。
ありがとうございました。
79 :
35 :2009/09/24(木) 11:56:35
>>60 記事の紹介、ありがとうございます。読んでみました。
記事では、C++でlock-freeを使って生産者-消費者モデルを実現していますね。
以下はすべてC++のWaitFreeQueueクラスとして実装されています。
・まずlock-freeで「排他」を実現するキューを実装。
この時点では「排他」だけですから、スレッド間の「同期」は実現できていません。
・次に、キューが空である間、消費者スレッドをループさせ続けることで「同期」を実現。
この方式では、キューが空であればCPUを100%消費します。
==> NATIVE_POOLING方式
・続いて、キューが空である間、消費者スレッドをスリープさせ続けるループを
組むことで「同期」を実現。 ==> SLEEP方式
・最後に、BOOSTのcondition(timed_wait/notify操作)を使う事で、
「同期」を実現。==> TIME_WAIT方式
(続く)
80 :
35 :2009/09/24(木) 11:59:49
(
>>79 の続き)
このC++ by DDJ実装と、
>>40 が紹介してくれたJavaの実装とを比較すると、
lock-free/wait-freeの意味に違いがあるように感じられました。
C++ by DDJ実装のTIME_WAIT方式は、JavaであればBlockingQueueクラスに相当しますが、
>>40 では、BlockingQueueクラスは(同期の実現はモニタ使用が前提だから)
lock-free/wait-freeではない、と定義しています。
これらの一見矛盾しているように見える事柄を、自分なりに以下のように解釈してみました。
・lock-free/wait-free単独では「同期を実現できない」
・ただし、lock-free/wait-freeとスリープ(あるいはモニタ/conditionなど)とを組み合わせた制御を
アプリケーション側で(たとえばクラスとして)実装することで「同期を実現できる」
誰も皆「排他」に関しては「実現できる」と見解は一致していますが、
この「同期」が「実現できる/できない」という解釈に関しては、人によって見解が
分かれているように思えます。違いは、「スリープ/モニタ/conditionなど」の使用を含めて
「できる」とする考え方と、それらは純粋なlock-free/wait-freeではない、とする考え方です。
難しい論争で、技術的な課題でもありませんから、私もこれ以上の考察は止めにします。
81 :
35 :2009/09/24(木) 12:10:08
>>70 レスありがとうございます。
>>80 の最後で書いたように、lock-free/wait-freeとスリープとを組み合わせた制御を
アプリケーション側で実装することによって「同期」は実現できますね。
# せっかく
>>60 がDDJの記事を紹介してくれていたのに、それを読まずに
>>69 を
# カキコしてたのが、まずかったと反省しています。余計な手間をとらせてごめんなさい。
リング遷移よりはスピンした方がいいとか、ある程度待っても何も来なかったら スリープとか、待機時の特性をアプリケーションがチューニングするやり方に なるのは、ハイパフォーマンス向けだと利点と言えるのでは。 まぁ、リング遷移が気にならない状況ならカーネルに任せていいと思うけど。 とりあえず、スピン待機は立派な同期だよ。CPU使用率をやけに気にしてるけど、 MP向けだとスピンじゃないと話にならないことも多い。
83 :
35 :2009/09/24(木) 14:21:36
>>82 (CASやスピンを用いた)lock-free単独による同期については、メニーコア、
あるいはその先(未来)にある超並列な世界であれば、並列システム全体から
見ると個々のコア(CPU)の無駄は無視できます。だから、その時代になれば
「lock-free単独による同期が常識」となっている可能性は十分に予測できます。
もしかすると、現在でも
>>82 が主張されているMP(?)向け用途、それに
HPC(High Preformance Computing)やCELLのプログラマにとっては、
既に「lock-free単独による同期は常識」なのかもしれませんね。
ただし、現在のPC向け汎用CPUはシングルコアかせいぜい4コアが主流です。
その世界では、いかに個々のコアを無駄無く使いつぶすかが、
性能設計上の大きな課題になります。ですから、現時点では、
「lock-free単独による同期は一般的ではない」、言い換えると、
一般アプリケーションにおいては「スリープなどと組み合わせない限り
(単独の)lock-freeでは同期は実現できない」と解釈しています。
論理的にはCASやスピンでも同期は実現可能である(立派な同期である)。ただし、
一般的な多くのケースにおいては、その方式は現実的ではないということです。
これもまた「できる/できない論争」の一種ですよね。
デュアルコアでさえスピンは使うって。 lock-free queueのcalleeが同期の機能を持ってるか、にこだわってるの? callerが同期処理をしなきゃならない、だとしても、lock-freeで同期してることに なると思うけど。そうじゃないなら、シーケンスロックはロックの機能を持たない とかいう変な話になるぞ? つーか、ノンブロッキング同期の一種だぞ、lock-freeもwait-freeも。
85 :
35 :2009/09/24(木) 14:51:24
>>84 同じ「待ち」でも、「排他(ロック)」と「同期」は別のものです。
「排他」による待ちは一時的です。もしもそれが長時間継続するようであれば、
それは「設計が悪い」のです(一般にはバグとして扱う)。
それに対して「同期」の継続時間は不定です。
最も長いケースでは、システム全体が終了するまで「待ち」状態が継続します。
また、共有キューを用いた「同期」を実現するには「排他」も必要です。
ただし、だからといって「排他」だけでは「同期」は実現できません。
「排他(ロック)」と「同期」を区別して、考え直してみてください。
lock-freeには「排他」機能があります。ですから「デュアルコアでさえ
スピンを使う」ことはあります。でも、lock-freeを単独で「同期」に
用いるのは現実的ではないと言っています。
というか「できる/できない論争」は止めにしませんか?私はこれで降ります。
> 一般的な多くのケースにおいては、その方式は現実的ではないということです。 ここの認識が勘違いしてると思うけどなぁ。 まぁ降りるならどうぞ。
lock-free queueの話で同期の話が出てくる時点で何かおかしい気がしている lock-free queueってのはこういうものだと認識しているのだけど…↓ マルチスレッドにおけるQueueのpushとpopの処理では、内部の変数の更新が衝突すること によって破壊されてしまう場合があるため、何かしらの機構を備えておく必要がある。 mutex等による排他制御ではコンテキストスイッチが発生し、それは時間的にシビアな場面 においては非常に遅くなる場合がある。 そのためコンテキストスイッチさせないようにあの手この手を尽くして (mutex等排他制御のためのプリミティブが使われていない)lock-freeなものを作る場合がある。 lock-free queueでは複数のスレッドからQueueに対してpush/popされても、内部でmutex等 による排他制御は行われず、コンテキストスイッチが起こらないため、複数スレッドから の高速なデータのpush/popが期待できる。 ↑何か間違ってる? Queue(待ち行列)という特性を見るかぎり、Queueを使った同期ってのがどういうものか イマイチ解らない。
if(v.empty()){/*待機コード*/} int i=v.pop(); 例えばこれも同期
ifじゃなくてwhileだった
>>88 それって、Queueを使うためにmutexやスピンロック等を使った同期であって、
Queueを使った同期ではないような…
もし仮にそのことをQueueを使った同期と言っているのであれば、それとlock-free queueとは
関連性薄くない?(べつにbool値のflagだとしても議論できるし)
もしかしてQueueとかもう話題的にあんまり関係なくて、
単純に、スピンロックやmutex等の排他制御、CASはそれぞれどういう時に便利ですか?
って議論だったりする?
>>88 empty()とpop()が別だから、複数スレッドだとrace conditionになるね。
どう見てもmutexもスピンロックも使ってないし、empty()じゃなくなった後に empty()がtrueにならないことが保証されてるqueueなら競合もしないよ
お互いに勝手なコンテキストを想定して話すから、会話が成り立ってない。
・読み手/書き手は単数なのか複数なのか ・一般例なのか状況限定の例なのか ・empty()はロックしないことを保証しているか(lock-freeならしているだろうけど) こういう重要な条件をお互いに伝える気も読み取る気も感じられない。
95 :
87 :2009/09/24(木) 18:25:37
while (v.empty()){}
↑こういうコード(ある状態が真になるまでループする)がスピンロックなのかと思ってた。
>>92 みると違うみたい?
96 :
としあき :2009/09/24(木) 18:34:00
> こういう重要な条件をお互いに伝える気も読み取る気も感じられない。 念
99 :
35 :2009/09/25(金) 02:21:30
>>87 lock-free queueを実装する視点であれば、その認識は間違っていないと思うよ。
>>90 >単純に、スピンロックやmutex等の排他制御、CASはそれぞれどういう時に便利ですか?
>って議論だったりする?
自分はlock-free queueを使う立場だから、そういう視点で
>>81 まで議論を続けてきました。
で、その後から議論が拗れてしまったわけですね。
何が原因かを考えました。自分は、(共有キューの競合による破壊を防ぐ為の)「排他」制御の為に
スピンを「使う」ことは「一般的である」けれど、キューが空の場合に「待つ」、いわゆる
「同期」の為にスピンを「使う」のは(汎用PC/CPUの世界では)「一般的ではない」という立場。
それに対して、いや、キューが空で「待つ」場合にも、スピンを「使う」のは(汎用PC/CPUの
世界であっても)「一般的である」というのが、相手の立場。
ある事柄に対して、それが「一般的である/ではない」という解釈は、一般常識論ですから、
それぞれの立場によって異なるのが当たり前です。そんな両者が納得できる結論を導くのは難しい。
だから、
>>85 では、これ以上議論を続けても不毛なので止めることを提案しました。
できません ↓ できます ↓ 一般的じゃないからできないようなもんです ↓ ハァ? って流れに見えた
私はこれで降ります ↓ 何が原因かを考えました ↓ 提案しました ワロタ
>>87 多分間違っていると思うよ
コンテキストスイッチは関係ない。
lock-free なキューのメリットは、lock-free でないキューより
(ロックしないから)アクセスの並列性が高まること。
もちろん競合するときには性能が落ちるけど、平均的には
性能向上が期待できる。
アクセスの並列性ってどういうこと? それが高いと何がうれしいの?
こんなケースで、こういうlock-freeなのを実装したら、 これだけパフォーマンスが向上しました・ ...みたいなのを挙げてみてほしい。 どうでも良いけど、jemallocでも、spinlockしているね。
>>103 ロックは重い処理だから、それなしにCAS等の手法で数十ステップで収まるloc-freeは
軽い(逐次実行時間が短い)ってことを言いたいんだろ。
ただ、コンテクストスイッチは関係ないと言い切っちゃうのは、もう......だなw
lock-freeの定義が各人の頭の中にしかないから1000までこの話題でも結論は出ない(キリッ
まず、スピンロックとlock-freeにおけるCASの違いは スピンロックは、単純に同じ動作(CAS)を再試行する lock-freeの実装では、単純に値を読み直す場合や全ての動作を最初からやり直す場合等いろいろあるが とにかく、「同じ値で再度CASを実行する」ということはしない。 wait-freeは、上記の「CASの再実行」が起こらない、ということだから 言い直せば、retry-freeとでも言えるのかも知れない。
あと、上のほうで「CASを使わなくてもメモリバリアがあれば云々」という話があったようだが CASが重いのは、CASに含まれるメモリバリア(バスロック)動作が重いのが理由なのだから CASを無くしたからってメモリバリアが必要なら、たいしてメリットは無くなる。 もし、「メモリバリアも無くしてかつwait-freeな実装が可能」というなら話は別だが。
>>108 > CASが重いのは、CASに含まれるメモリバリア(バスロック)動作が重いのが理由なのだから
メモリバリアとバスロックは別の概念だぞ。
たとえばIA-64には、メモリバリア無しのCAS命令(ニーモニック:cmpxchg)と、
メモリバリア有りのCAS命令(cmpxchg.acq や cmpxchg.rel)がある。
そもそも、メモリバリア自体はそこまで重い操作じゃない。
特に、C++0xでの memory_order_acquire, memory_order_release に相当する
メモリバリアは、自身のスレッド内での順序づけを保証するだけなので、
他CPUとの通信を必要としないためコストもかなり小さい。
で、これまで話題になっているwait-freeなlinked queueなど、
多くのlock-free, wait-freeアルゴリズムの実装では、
この acquire, release 相当のメモリバリアで十分だ。
見よう見まねでスピンロック実装して動作テストしたら標準のCriticalSectionより劇おそだったのは苦い思い出:プライスレス(´・ω・`)
Win32のCriticalSectionの激速の理由は プロセッサを判定して、可能ならばunlockにmovを使ってバスロックを避けているから と俺は勝手に想像している。
push/popを必要最低限にして、 適宜pause(rep; nop)を入れれば良いだけ。
114 :
234 :2009/10/01(木) 20:17:23
>>112 コンテキストスイッチが無いときはカーネルに入らずに、単にロックカウントをアップしてるだけだからだよ。
>>114 いやそんなの当たり前だし。
「単純なスピンロックより速い(
>>111 )」理由が何故か?だよ。論点は。
>>115 非コンテキストスイッチング時はアセンブラで10数命令しか実行して無いんだから速いよ。
それに
>>111 のコードを見なければなんともいえない。
だから、その命令の中に、lock xadd とかの重い命令があるんだよ。
コンテキストスイッチが無いから速い、とか アセンブラで10数命令だから、とか 偉そうな態度の割に、底が浅すぎる。
お前も相当えらそうだが。
無知が知ったかぶって偉そうにしながら恥を晒してるのとは違うみたいだけど。
間違っているというだけで何が間違っているか書かないやつは大抵ハッタリだわな。
void __stdcall trylock(volatile int *spin) { __asm { mov ecx, spin; mov edx, 1; xor eax, eax; lock cmpxchg [ecx], edx; } } void __stdcall unlock(volatile int *spin) { __asm { mov ecx, spin; xor edx, edx; mov eax, 1; lock cmpxchg [ecx], edx; } } void __stdcall trylock_nlk(volatile int *spin) { __asm { mov ecx, spin; mov edx, 1; xor eax, eax; cmpxchg [ecx], edx; } } void __stdcall unlock_nlk(volatile int *spin) { __asm { mov ecx, spin; xor edx, edx; mov eax, 1; cmpxchg [ecx], edx; } } void __stdcall unlock_nbl(volatile int *spin) { *spin = 0; }
DWORD readtsc() { DWORD v; __asm { rdtsc; mov v, eax; } return v; } int main() { const COUNT = 1000; CRITICAL_SECTION cs; InitializeCriticalSection(&cs); volatile int spin = 0; int st = readtsc(); for (int i = 0; i < COUNT; ++i) { EnterCriticalSection(&cs); LeaveCriticalSection(&cs); } printf("%u clocks at %s\n", readtsc() - st, "CriticalSection"); st = readtsc(); for (int i = 0; i < COUNT; ++i) { trylock(&spin); unlock(&spin); } printf("%u clocks at %s\n", readtsc() - st, "CAS"); st = readtsc(); for (int i = 0; i < COUNT; ++i) { trylock_nlk(&spin); unlock_nlk(&spin); } printf("%u clocks at %s\n", readtsc() - st, "CAS(lockプリフィックス無し)"); st = readtsc(); for (int i = 0; i < COUNT; ++i) { trylock(&spin); unlock_nbl(&spin); } printf("%u clocks at %s\n", readtsc() - st, "CAS(movでunlock)"); }
ほれ、ベンチ用意したぞ。 シングルスレッドで、ロック獲得が必ず成功する場合の数字のみ。 実際はカウンタ持ってるから単純なcmpxchgじゃなくxaddで正負と0を駆使して判定してるだろうし ロックを獲得できなかった場合にブロックに移行する処理もあるだろうけどな。 まあ見難いが、面倒くさかったから TABのインデントは見たい人が自分でやってくれ。
これでもまだ「コンテキストスイッチが」「命令数が」と言いたいなら ご自由にどうぞ。
乙 しかしお前がどのレス書いたやつで何を主張したいのかがわからん。
実行してみなきゃ結果の意味するところもわからんからね。
まあ俺は
>>112 >>115 >>117 とかだが。
関係ないが、stdcallとか、全然意味なかったな。
全部展開されてるし。
しかも、Enter/Leaveもレジスタにコピーされてレジスタ間接コールになってる。
129 :
128 :2009/10/02(金) 01:04:01
130 :
128 :2009/10/02(金) 01:27:59
まあ一応、俺の手元での数字を出しとく。
rdtscで計ってるので、別プロセスに割り込まれない限り
何回やっても似たような数字になる。
18065 clocks at CriticalSection
39098 clocks at CAS
13700 clocks at CAS(lockプリフィックス無し)
19025 clocks at CAS(movでunlock)
1番上が、単純にCriticalSectionをEnter/Leaveしたもの。
次が、「教科書通り」のCAS(lock+cmpxchg)を使ったスピンの取得と解放。
おそらく、
>>111 もこれに似たコード(取れない時のループは無し)を書いたと思われる。
3番目は、上のコードから、バスロックを除いたもの。バスロックのコストを示すため。
4番目が、
>>112 に述べた、unlock時のバスロックを避けるようにしたもの。
結論としては、
>>112 の推測が確信に変わっただけ。
spinlockの話題
>>111 が、CASにすり変わっている件について。
「教科書通りのスピンロック」って、普通は xchg (test-and-set)でロックを取って、movでアンロックじゃねーの? それとも最近の教科書は test-and-set より先に compare-and-swap を教えるのかな?
一般のプロセッサでxchgが1バスサイクルで実行される保証なんて無い。 というより、普通は読みと書きになる。(x86が特殊なだけ) だから、ロックを取得するにはCASが必要。
あ、ごめん TASならば確かにCASである必要は無いね。
>>135 それはメモリバリアの問題であって、movかCASかは関係ない。
mov命令がreleaseメモリバリア効果を持っていればそれで十分だし、
逆に>110で挙げたようなメモリバリア無しCAS命令では不十分。
>>135 それはspinlockを使う側が考慮する問題であって、
作る側は無視して良い。
W2kSP4, Athlon 64 X2 3800+, VC6SP6+PP5, 最適化無し 50239 clocks at CriticalSection 49180 clocks at CAS 21132 clocks at CAS(lockプリフィックス無し) 32103 clocks at CAS(movでunlock)
>>136 それがメモリバリアの問題だっていう、そんなことわかってるよ。
そして、「一般的なmov」はメモリバリアの機能など持っていない事
さらに、「(次に書く)このスレで"一般に"用いられるCASという用語」はメモリバリアを持っているもね。
もちろん、CASというのがメモリバリアとは直接は関係ないってことだって充分知ってるよ。
(そうでなければ、lockなしのcmpxchgなんてもの出すわけ無いだろ)
だけどこのスレで一般的にCASと言ったら
「アトミック操作で用いる事が可能なCAS」のことが普通だろうに。
「一般的なmov」つまり、普通のロード/ストア操作はメモリバリアを持っていないのだから 普通のスピンロックの実装では、アンロック処理に movではなくメモリバリアを持ったTASやCASを使う。 (それらはロック獲得処理の段階で存在が示されている) だから「普通はmovでアンロック」などということは有りえない。
Windows Vista 64bit SP1, Core2DuoE6750, Microsoft Visual Studio 2008(VC Version 9.0.21022.8 RTM)
/O2 /Ob2 /Oi /Ot (実行速度で最適化、インライン関数は展開可能な関数すべて展開)
101192 clocks at CriticalSection
67904 clocks at CAS
20424 clocks at CAS(lockプリフィックス無し)
88688 clocks at CAS(movでunlock)
/Od /Ob1(最適化なし、インライン関数は展開しない)
108568 clocks at CriticalSection
99976 clocks at CAS
24184 clocks at CAS(lockプリフィックス無し)
65280 clocks at CAS(movでunlock)
>>130 の結果が謎すぎる
>>139 アトミック性とメモリバリアは別の概念だぞ。
CASがアトミックなのは当たり前であり、俺もそんなことに
文句をつけているわけじゃない。
x86におけるlockプレフィックスのないcmpxchgは
SMP環境ではアトミック性が保証されないから
(正しい意味での)CASとは言えない。
でも、>110で挙げたのは「アトミック性は保証されているが
メモリバリア効果を持たないCAS」だ。
CASとは「あるメモリ位置に対する内容の取得・比較から代入までが
アトミックに行える操作」であり、メモリバリア効果、つまり
「前後の命令との間でリオーダーを行わないという保証」は必須ではないと
俺は言っている。
# 実際に、C++0xのatomicライブラリではそのように定義されているし。
「普通のロード/ストア命令はメモリバリアを持たない」と言うのなら、
メモリバリアを持つロード/ストア命令を定義して、それを使えばいい。
何故わざわざCASやTASのような複雑な操作を持ち出す必要がある?
ちなみに、x86のmov命令は(初期のバグ持ちプロセッサを除いて)
デフォルトでreleaseメモリバリア効果を持っているぞ。
はいはいごめんよ。 全部俺が悪かったよ。
ちらっと見ただけなんだけど、「volatile つけた変数に排他性は無いよ」 ってことをグダグダ言ってるみたいだけど、そんなの当たり前では? 都市伝説もくそもねーよ
acquire/releaseバリヤって、 「そのスレッドでのメモリアクセスについて」限定? ↑のスライドだと前後の命令を・・・となってるけど
当たり前よ っつかどういう意味で聞いてる?
菊池バリヤー!
「バリア」って概念には 「メモリアクセスがコーダーが記述した”順”に実行されることが 保証される」っていう以上のものは含まれていない(例えばインク リメント操作がアトミックになることまでは保証されない)と認識し ているのですが。当たってます? ネットに散らばっている情報にはブレがあると思えるし、正直、 勉強不足ではっきりと分からないところがあるので質問します。
>>150 それで正しい。
ちなみに、マルチスレッドの世界には「バリア同期」っていう全然別のものもあるので、
メモリバリアのことは「メモリフェンス」と呼ぶようにした方がいい。
152 :
デフォルトの名無しさん :2009/10/03(土) 19:15:56
>>151 ありがとうございます。頭の中がすっきりしました。
どうでも良い事だけど。 spinlockを奪い合った場合、 先に取ろうとした方が取れず、 後から取ろうとした方が取れたとしても、 動作としては正しいんだよね。
154 :
デフォルトの名無しさん :2009/10/03(土) 21:37:43
spinlockはアンフェアだからそれで正しいね。
>spinlockはアンフェアだからそれで正しいね。 それは答えになってるのか??
間違いではない=正しい という論理がわからないのか? どうしょうーもねーな
正しいのか?って言ってんじゃなくて 答えになってるのか? って言ってんだけど。
答えにはなっているように見える。「正しいのか?」という問いに「正しい」と答えている。 その答えが正しいのかどうかは別の話。
>>155 説明になっているかどうかはともかく
答えにはなっていると思うんだが。
火元の人 やり方が理解できない質問者 俺に分からないならこのスレにも理解できる奴いないんじゃね、とか思っていて、 それが態度にも滲み出ている 煽る人 分かってるつもりだけど分かってないで煽り続ける こいつを見た火元は「やっぱり分かってる奴いないんじゃないか」と思いこむ 住人タイプA 一目で分かるがお前の態度が気に入らないしコード示すのマンドクセ つーかこの説明で分かれボユゲ 住人タイプB みんな何言ってんだかわかんね ちょっと違うけどこのパターンに似てる
posix準拠のオーソドックスなやり方しかしない俺にはこのスレは不要なようだ おまえら何言ってるかわかんねぇーしw
>>162 自分からPOSIXスレッドとかに関連したネタをふればいいんじゃないかな?
まあ正直なところ、ここは相談室スレなんだから、あまりにもハードウェア寄りな専門知識が
必要な話題については、できれば「並列化について語る」スレで熱く語ってくれって感じはしてる。
あっちはハード(マルチプロセッサ/マルチコア)全然オケーなスレなんだから。
単に自分の付いていけないレベルの話題を締め出したいだけに見える
ということにしたいだけにも見える
つーか俺はposix準拠な世界で生きてきたので。 おまえらよくposix非準拠な話題で盛り上がれるなーw
>>166 CASやメモリバリアなどはpthreadライブラリの実装者にとっても
必須の知識だよ。
POSIX厨としか言いようがない
pthreadにはアトミック操作が定義されてないから、 単なるカウンタのインクリメントでも いちいちロックしなきゃならんのが嫌だ。
なんでPOSIXで厨なんだよ(´・ω・`)
POSIXスレッド以外の話題ってだけで叩くなら完全に厨だろ
他人を厨と決めつける人が厨に見える
何でも鸚鵡返しすれば反論になると思ってるだろ
baka
/\ ┌┐ ┌┐ ___ ___ / __ \ /\ ..||.. /\ || ___ \\ \ / / .\ \ \ \ .||. / / ┌──┘└──、\\  ̄  ̄ / / .\ \ \/ .||. \/ └──┐┌─ 、| |__| / / ┌──┐.\ \ ┌───┘└───┐ .|| || ..\/ └┐┌┘ .\/ └───┐┌───┘ / / || ┌┘└┐ /\ .||. /\ / / / / └┐┌┘ / / .||. \ \ / / / / ┌─┘└─┐ \/ ..||.. \/ \/ / / └────┘ └┘ \/ ....、 ....................--------、, i~゙7 r‐ッ !゙゙.! ! ! : !―――;;;;;;''''''''ゝ ,,ノ゛ ._ / ./ .,! .,! ! ! .,..............! ヽ..........-、 | |./ / .l、,`''-./ ./ ! ! | | ――ーッ .iー''''''''i | | l'-‐゛ `゙ッ .ゝ、 .| | | ,! ./ ./ ! ! ../ .,! /.,r'"\,/ .!ー′ ./ .,! . / ./ | │ .,./ ./ ,..‐" / . / / ./../ ./ .l゙ .r'"./ ゝ/゛ : ,,-'゛./ .〈 / .'|,゙,゙,,,, " .`゛ ゙'''"
その “全米” はグアム島を含むのでしょうか。
グアム、どうなんだろ。州に昇格すればいいのに。まあ、しないだろうけど。
181 :
デフォルトの名無しさん :2009/11/03(火) 00:02:53
スレッドを終了させるときは_endthreadexじゃなく そのままreturnでもいいのか?スタックの開放されない?
良い。 mallocで取ってきた領域をfreeしなくて良いのと同じくらいに。 スタックとやらは、_endthreadexとは無関係。
freeしろよ
スレッドに強くないのに書き込んでみる。
ttp://msdn.microsoft.com/ja-jp/library/hw264s73 (VS.80).aspx
>ただし _endthread または _endthreadex は、_beginthread や _beginthreadex の
>パラメータとして渡されたルーチンからスレッドが戻ると自動的に呼び出されます。
ってことで、returnすれば問題ないかと。
どちらかというと
>_endthread と _endthreadex によって、C++ デストラクタはスレッドで保留状態になり、呼び出されません
なので、呼ばないほうが好ましいような。
182は無かった事にしてください。 んゆ。
186 :
184 :2009/11/03(火) 14:42:55
スレッドに強い人に補強して欲しいのだけど、それとも184の認識で問題なし?
Microsoft Visual Studio\VC98\CRT\SRC\THREADEX.C んゆ。
問題なし
189 :
デフォルトの名無しさん :2009/11/03(火) 22:08:15
スレッド識別子って何なんだ? 何に使うの?
殺したり、止めたり。
他スレッドの変数の中身知ることってできないかな?
メモリ空間は共有しているので、アドレスがわかれば普通に参照できる。
win32のインターロックをクリティカルセクションと 同じように使ったら早くて驚いた。 両者の内部的な違い・利点・欠点てなんですかね?
そもそも用途が違うんじゃない? インターロックは変数1個ぶんの更新しかできないでしょ? インターロックを使ってクリティカルセクションと同様のものを作ることはできるだろうし、 クリティカルセクションを使ってインターロックと同様のものを作ることもできるだろうけど、 そういう話?
インターロック一発で出来ることならインターロックで。
win32のクリティカルセクションは衝突しなければインターロックと同じくらい早いんだなこれが
いや倍くらいは遅いだろう。
んだ。インターロックで済むならそれが数倍早い。
199 :
193 :2009/11/05(木) 19:29:23
今以下のクラスでクリティカルセクションと同じように扱ってテストしてるんだ。 class InterLock { private: LONG m_Flag; public: void Enter() { while(InterlockedCompareExchange(&m_Flag,1,0)) Sleep(0); } void Leave() { InterlockedCompareExchange(&m_Flag,0,1); } public: InterLock() { m_Flag = 0; } virtual ~InterLock() { } };
200 :
193 :2009/11/05(木) 19:30:08
こっちはクリティカルセクション晩 class CriticalSection { private: CRITICAL_SECTION cs; public: void Enter() { EnterCriticalSection(&cs); } void Leave() { LeaveCriticalSection(&cs); } public: CriticalSection() { InitializeCriticalSection(&cs); } virtual ~CriticalSection() { DeleteCriticalSection(&cs); } };
201 :
193 :2009/11/05(木) 19:43:57
//グローバル変数 ロッククラス g_Lock; int g_i = 0; // 三つのスレッドで以下を走らせる void Run() { for(int i=0; i<10000000; i++) { g_Lock.Enter(); g_i++; g_Lock.Leave(); } } int main() { //3つのスレッドでRun()を走らせ、スレッド終了まで待機 (...省略) cout << g_i << endl; cout << time.result() << endl; return 0; } 結果 クリティカルセクション 35秒 g_i = 30000000 インターロック 5.5秒 g_i = 30000000 ロッククラス無し 0.16秒 g_i = 21203536(整合性無し) 環境 OS:win xp CPU:core2duo1.8G メモリ:3G
ソースまともに見てないけど、CSがもしインライン化されないなら性能的には勝てない だろうしなぁ まぁ、asm読めば全て分かるだろうけど
TryEnterCriticalSection ~ Sleepだとどうなるの、っと。 threadをCPUと1:1にbindしたらどうなるの、っと。 timesliceを変えたらどうなるの、っと。 結果は書かない方が良い。
204 :
193 :2009/11/06(金) 07:01:38
>TryEnterCriticalSection ~ Sleepだとどうなるの、っと。 これだけやってみた。 上記のテストだとインターロックとの差は0.5秒内、 つまりほとんど差がなくなった
プロセッサ数が2以上ならSpinWaitにしたらどうなる? あとインターロックのIncrementでダイレクトアップデートにしたらどうなる?
違うネタだけど。 #include <windows.h> #include <tchar.h> #include <stdio.h> #include <stdlib.h> #define THREADS 64 #define LOOPS 123456789 struct SData { LARGE_INTEGER m_cntBegin; LARGE_INTEGER m_cntEnd;}; DWORD WINAPI thread(LPVOID pArg); int __cdecl cmpForSort(const void *pArg0, const void *pArg1); int _tmain() { int i; HANDLE ahThread[THREADS]; SData aData[THREADS]; LARGE_INTEGER diff; for (i=0; i<THREADS; i++) ahThread[i] = CreateThread(NULL, 0, thread, &aData[i], 0, NULL); WaitForMultipleObjects(THREADS, ahThread, TRUE, INFINITE); qsort(aData, THREADS, sizeof SData, cmpForSort); for (i=0; i<THREADS; i++) { CloseHandle(ahThread[i]); diff.QuadPart = 0<i? aData[i].m_cntBegin.QuadPart - aData[i-1].m_cntBegin.QuadPart: 0; _tprintf(_T("thread: %d, diffBegin: %I64d, clock: %I64d\n"), i, diff.QuadPart, aData[i].m_cntEnd.QuadPart-aData[i].m_cntBegin.QuadPart); } return 0; }
DWORD WINAPI thread(LPVOID pArg) { SData *pData; DWORD value; float sum; pData = (SData *)pArg; QueryPerformanceCounter(&pData->m_cntBegin); __asm { mov ecx, LOOPS fldz LOOP_: fadd QWORD PTR value dec ecx jnz LOOP_ fstp DWORD PTR sum } QueryPerformanceCounter(&pData->m_cntEnd); return 0; } int __cdecl cmpForSort(const void *pArg0, const void *pArg1) { LARGE_INTEGER diff; diff.QuadPart = ((SData *)pArg0)->m_cntBegin.QuadPart - ((SData *)pArg1)->m_cntBegin.QuadPart; if (0 > diff.QuadPart) return -1; if (0 < diff.QuadPart) return 1; return 0; }
同じ処理なのに所要時間がブレるとか、 先に開始したthreadよりも、後から開始した方が早く処理を終えるとか。 そういうのが起こりうる。 computer gameでmulti threadの利用に消極的な理由の一つだと思う。
209 :
193 :2009/11/06(金) 23:12:33
>>205 >インターロックのIncrementでダイレクトアップデートにしたらどうなる?
1.3秒だった
>SpinWait
これC#じゃん
スピン待機はC#限定じゃなく一般的な概念だ
スピンすると余計遅くなりそうだな。 一般的な使用状況に比べて処理と競合がタイトすぎるせいかな多分。
ああつまり3スレッド同時じゃなくて1スレッドで3回繰り返した方が速いとかっていう状態ね。
あーいやいや、これだとちょっと書き方がおかしいな…まあいいや
214 :
193 :2009/11/07(土) 19:49:07
スピンロックは信頼性がないという話を聞いたような。 さて上記のベンチですが、1スレッドで3回繰り返したほうがずっと早いです。 衝突したときに別の処理をせずに待つ場合はシングルスレッドにした方がいいかも。
スピンロックに信頼性が無かったらどうすんだよw 全然仕組みとか分かってなくて使ってる匂いがぷんぷんするな
スピンロックとスピンウェイトは基本的に別物です。
それと信頼性に何の関係が?
スピン待ちの話をされてスピンロックどうこうと返すのがおかしい
上の人じゃないけど、スピンロックはスピンウエイトを使ってやってるかとおもてたよ(´・ω・`)
spinlockでlockできる保証は無いね。 偶然上手く動いているだけ。
◆0uxK91AxIIで検索したら、NGしてもいいくらいトンチンカンな奴だな
トリップ付けるような奴だもの。
トンチンカンなんて久々に見た おやつあげないわよ
抜作先生の方がまだ新しいな。
マルチスレッド対応の基数木のアルゴリズムって どうやって記述すればいいのでしょうか? CかC++で探しています。
読み込みと書き込みが1スレッドずつの場合でもメモリ破壊って起きるのでしょうか? たとえば、ある変数をメインスレッドで読み込み続け、 複数のサブスレッドで、クリティカルセクションを用い、書き込むといった場合です
>>226 とりあえず破壊読み出しメモリだと死ぬよね。
パソコンのネジ外して開けると見えてくるメモリの部分をハンマーで叩く
ハードウェア的な話題もするんか
宇宙線による確率的なビット反転は防ぎようがない
232 :
226 :2009/12/23(水) 10:10:00
データが飛ぶという意味でのメモリ破壊です ハード的にどのように動作しているのか分からないのですが 同アドレスに同時にアクセスされることによってメモリ破壊が起きるのでしょうか?
書き込みをクリティカルセクションで同期して、クリティカルセクションを抜けたところで可視性が保証されたとしても、 読む方が書き込み中にその変数を見る可能性があるなら、少なくとも意図しない値を読む可能性はあるんじゃない? (+不変な変数見てると思われるかもね) 要求次第だけど、 この手のポーリングするやつは、次に読めればいいからその瞬間のスナップショットで十分だと思うので、 Atomicな操作用のAPI使うとか、書き込みがAtomicであることが保証されるならvolatileだけでもいいかも。 その変数の読み書きだけ同期とっても、読んでる間の書き込みは防げても、 読み込みが終わってクリティカルセクション抜けたあと、それで処理しようと思ったら もう書き換わってることもあるし。 読んだ値の処理が終わるまで書き込ませないなら、話は別だけど。
昔使ったタイマ LSI でラッチ→lo-read→hi-readって いう約束ごとのあるやつがあったな。hi-readでラッチ が外れる奴。word-read 命令が使えるかどうかは CPU 次第。
>>226 ハードや操作による。
つーか、まずは「アトミックな操作」という概念をどっかで調べとけ。
例えば、x86のCPUなんかだと、どういう操作がアトミックかはIntelが規定している。
アトミックな書き込みなら、別のコアからの読み込みが割り込む可能性は無い。逆に
アトミックでない書き込みなら、例えば半分くらい書き込んだところで別のコアが
読み込む可能性があるということ。
x86なら、厳密な規定はIntelの英語版サイトに落ちてる。32bitアラインドなreadや
writeは確実にアトミックだ。相当古いx86以外はキャッシュアラインドなら大丈夫。
read-modify-writeはLOCKプリフィクスが無い限りアトミックではないが、xchg
命令はLOCK#が自動的にアサートされるのでアトミックだ。
まぁ、アセンブラを直接叩くんじゃなければ、イントリンシック命令を調べておけば
十分だが、その裏でどういうCPUの動きをしているかは理解しといた方がいい。
つーか、低水準の話と高水準の話で全然違いすぎるんだよな。俺はどっちの話でも
構わんけど、分けた方がいいのか?
236 :
226 :2009/12/23(水) 12:53:08
ありがとうございます もっと勉強します
>>232 そんな事は起きないようにハードウェアが作られてる
物理的なメモリへのアクセス経路は1個しかないから、同じアドレスに同時にアクセス
なんて事は出来ない
命令が書いた順に実行されるかとか、他のコアやスレッド云々は
>>235 の通り
クリティカルセクションを用いって書いてあるから、なんとなくWindowsかと思ってた。
>>235 ここはム板だから低水準の話はついていけないと思う
>>237 > 物理的なメモリへのアクセス経路は1個しかないから、同じアドレスに同時にアクセス
> なんて事は出来ない
いつの時代の人?
ん?今はどこが違うの?
>>235 x86は巨視的には古典的設計だからまだ理解しやすいけど、PPCなんかだとリオーダー
とかが剥き出しになってくるからさらにごちゃごちゃするんだよな
そこでeioioですよ!
間違えた、eieioだった イーアイイーアイオー!
エイッエイッオッー
この辺の話題が体系的に書かれてる教科書が欲しい
開拓が進行中のジャンルだから、書いたそばから陳腐化しそうでなかなか難しいかも しれないな
何をもって高性能とするかをはっきりさせたいな シングルコア100%アイドル3コアでできることを4コア25%ずつで処理することに意味はあるの?
>>249 に追記
並列処理の有利はわかるけど、これからは直列処理も並列化しようとしてるんでしょ
そんなの意味ないよねという話
1コア100%3コア0%ってCPUがボトルネックになってんじゃねーの
何を言ってるの?
>>249 は軽くエスパーが日本語に翻訳しないと分かりづらい
4スレッドにしたら全部25%になっちゃうような処理までマルチスレッドにする
意味あんの、って言いたいんだろうし、だからCPU屋は2コアや4コアで現状維持
しながら別の進化の方向性を探ってるのも事実
だがそもそも、そういう微妙なケースにまで頑張って適用しようぜMTマンセー、
というようなスレではないので、そんな的外れなこと言われても一瞬何の話だか
分からんし、今更何をとしか言いようがない
>>253 余ってるCPUに仕事振る余地のない処理なら
それでいいんじゃね?
>>249 の問題提起自体が微妙
アムダールの法則くらいで十分じゃねーの?
そもそも並列化できない処理まで並列化しようとしてるなんて話は聞いたこともない。 誰が言ったんだそんなこと。
質問させてください。 【OS】 UNIX/LINUX 【言語】 C言語 【実行環境】 gcc 【その他特記する事項】 メインスレッドからn個のスレッドを作成->全ての終了を待つという場合、 int i; pthread_t id[n]; void* res[n]; for (i=0; i<n; i++) pthread_create(&id[i], NULL, funcptr, arg); for (i=0; i<n; i++) pthread_join(id[i], &res[i]); こんな感じで大丈夫でしょうか? それとWindowsにあるWaitFor〜みたいに複数待つというのは無いのでしょうか?
261 :
デフォルトの名無しさん :2010/01/26(火) 00:12:16
スレッドを終了させないままアプリを閉じた場合 やっぱメモリリークとか起きるの?
環境を想定しないとなんともいえない。
>>261 OS破壊されるぞ?いいのかそんなことしても
>>261 ja.wikipedia.org/wiki/メモリリーク
破壊されるようなOSなんか使うなw
MTでそんな脆いOSはちょっと想像付かないなw 携帯の奴とかはどうなんだろう
267 :
デフォルトの名無しさん :2010/01/26(火) 16:15:09
問題(1) 名前を入れる入力ダイアログ1つとボタンを1つ表示し,ボタンを押したときは時間に応じて, 05時〜11時 「おはようございます,○○さん」 11時〜17時 「こんにちは,○○さん」 17時〜05時 「こんばんは,○○さん」 と表示するJavaScriptプログラムを作成しなさい。
断る。
269 :
デフォルトの名無しさん :2010/01/26(火) 16:24:21
キミの実力を見せてみろ
マルチスレッドと何の関係が
271 :
デフォルトの名無しさん :2010/01/26(火) 16:32:31
スレ違いでした。 すいません・・
VCでマルチスレッドアプリをトレース実行してるとかなりの頻度でOSごと固まるんですが、 マルチスレッドの場合のデバッグはデバッガ使わないのが普通なんですか?
PCが貧弱
嫁が貧乳
ユーザが頻尿
>>272 詳細なテキストサービスをオフにすると少し幸せになれるかも。
ATOK使いの俺には無縁な話。
最近スレッド使い始めました。 クリティカルセクションとかインターロックで変数を共有するのは なんとなく分かりました。 例えばCRITICAL_SECTIONを使う場合、アプリケーションで一つ用意すれば よいのでしょうか? 極端に言えばCRITICAL_SECTIONをグローバル変数として定義して、 EnterCriticalSection等を使えばよろしいのでしょうか?
トイレに例えるなら何個個室があっても鍵がすべて連動してトイレにはひとりしか入れないってことだぞ それでいいのか?
それでも良いが性能は良くない 性能向上のためにスレッドを使っているわけではないのなら、別に構わない 無理にシングルスレッドで処理するよりマルチスレッドの方が可読性が高くなることもあるからな 性能を上げたいのなら一人がどこかでロックを握ってる間全員が待たされるような構造は良くない
280 :
277 :2010/02/03(水) 00:18:41
なるほど。問題点の指摘ありがとうございます。 では、3つスレッドがあるとして、1つは無関係で2つのスレッドで 変数を共有する場合は、クリティカルセクションをどう使えば よろしいのでしょうか? 各スレッドループ中にCRITICAL_SECTIONを定義してりようすればよろしいのでしょうか? 何か根本的に勘違いしている気がしている気がします。
共有する変数がグローバルで1個しかないのならクリティカルセクションもグローバルで1個でいいよ
282 :
277 :2010/02/03(水) 00:50:34
現在は全体からアクセスできる変数が一つです。 一気にやろうとはしないで少しずつ複雑なパターンを試してみます。 あと環境はWindowsです。失礼しました。
まあロックが1つで済むならデッドロックとか考えなくて済むし 可能ならその方が悩まない。 パフォーマンスの問題は、占有期間次第とも言えるから。
クリティカルな部分一個をトイレの個室一つと考える
たまに鍵かけないやつがいてトラブるんだ
そうするとトイレの中に トイレがあって、その中にまたトイレがないと 説明不可能だろ。 トイレはネストできねーだろ
そうかクリティカルセクションはネスト出来たか
じゃあトイレがバスルームにあるということで
階層数に制限があるからダメ。
トイレ中に地震がくるのと 小便中に大便を催すのと どっちが我慢できる?
メモリバリアとmutexの関係が解りません。 メモリバリアとmutexがどういうものか。とかじゃなくて、 関係性とか、必要とされる場面について解説してあるサイトないですか?
メモリバリアかアトミック命令が無いとMutexは実装出来ない
>>286 クリティカルセクションのネストって必要かな?
クラスのスレッドセーフなメソッドから同クラスのスレッドセーフなメソッドを呼び出す場合とかにあると便利かも そういう動作を意図しなかった場合にバグらないっていう利点もあるね
同クラスなら同期処理しないプライベートメソッドを呼び出すのではないか
たとえば口座aから口座bに振替をおこなうには、 口座aと口座b両方のロックを取る必要がある、 という典型的な例は?
それは二つのCSをロックするだけでネストじゃないんでね?
こんな話題とメモリバリアの話題が同時進行するってかなりカオスな気がする
両方とも、a→bの流れならトランザクションだけでよくないか?
スレッドがA、B、C、Dの4つあって かならずA、B、C、Dの順番で仕事が 終わるようにするには どんなアルゴリズム使えばいいのですか?
スレッド化する意味あるのか? B,C,Dは寝かせておいて、Aが自分の仕事を終えたときにBを起こせばいいんじゃないか
スレッドの終了処理を順番にやる必要があるってことかな。 終わるタイミングを調整したいだけなら、 BがAの終了を待つ CがBの終了を待つ DがCの終了を待つ って感じにやれば順番に終われるんじゃね?
そしてAがDの終了を待てば完璧
Eに管理してもらう
どうやるのか全然わからない たすけて
Aの処理終了の際に2個のスレッドで破れるBarrier1を待つ Bの処理開始の際に2個のスレッドに破れるBarrier1を待つ Bの処理終了の際に2個のスレッドに破れるBarrier2を待つ Cの処理開始の際に2個のスレッドに破れるBarrier2を待つ Cの処理終了の際に2個のスレッドに破れるBarrier3を待つ Dの処理開始の際に2個のスレッドに破れるBarrier3を待つ
>>310 >スレッドで破れるBarrier
こんなことすると破綻すると思うのですが
それは何か新しい概念なのでしょうか?
>>311 >>294 のバリアのことだよ。
2個のスレッドがバリアに到達した瞬間にバリアが破れて同時に進行を再開する。
Wikipediaより…
並列コンピューティングにおけるバリア(英: Barrier)とは、同期方法の一つであり、
ソースコード中でスレッドやプロセスがある箇所で停止し、
他の全てのスレッドプロセスがバリアに到達するまで進行しないようなものを示す。
同期なり待機って言った方がわかりやすいな
追加削除順序を保持しつつ 効率的にアクセス可能なデータ構造って何があるの?
二分木
>>316 マルチスレッドの2分木のサンプル
教えて
>>315 Skip list.
実装例は java.util.concurrent.ConcurrentSkipListSet とかかな。
C++のマルチスレッドの本って どんなのがありますか? Intelの本は使い方しか書いてないで 困ってる
正直、使い方だけしか提示しようがない気がする どこもかしこも開拓中で、定番というものが無い
>>319 Java並行処理プログラミングマジオススメ。
直接同じことは出来なくても、考え方は大いに参考になる。
volatileだけはC++と全くの別物なので注意だけど。
boost.threadのfutureでJavaのExecutorフレームワークに近いことが出来そうだなぁ。
>>321 その程度の書籍薦められても困るんだよ
もっとまともな本持って来い
>>322 もっとまともな本があるなら俺も知りたいけどね。
326 :
デフォルトの名無しさん :2010/02/22(月) 16:37:56
begintreadexを使ったときはclosehandleを使わないといけないらしいけど CloseHandle((HANDLE)_beginthreadex()); こんな感じでいいの?
beginthreadexが返したハンドルを渡すのかと聞いているのならYES
_beginthreadexはなんで整数型で返すんだろう
Win32の型を持ち込みたくなかったからじゃないの。
意味も無く汚くはしないしな、いくらMSでも
void *じゃだめなのか
それだと32bitであることを強調できないからやめたんじゃないかな
一応今はuintptr_tだしな まぁ毎度のレガシーの枷なんだろうし、仕方ないっつーか正直どうでもいい
どちらかというとマルチコア絡みの質問ですが テンプレにある該当スレは過疎ってるぽいのでこちらで質問させていただきます Q1. Windowsはスレッドコンテキスト切替時、汎用レジスタ同様にxmmレジスタを待避/復帰しますか? 主にWindows 7 (32 bit)とWindows 7(64 bit)について知りたいですが、他のも回答いただけると有難いです Q2. そもそもCore i7のSIMDモジュールってコア毎に独立してますか? 独立してるっぽいけど、確証となるブロックダイアグラムみたいなのがIntelのドキュメントを漁っても見つからないorz Q3. Core i7の分岐予測メモリって、コードが共通なら全スレッドで共通?それともスレッドコンテキスト毎にきちんと別統計になるんでしょうか? Q4. VC(2008)付属ライブラリの数学関数(おそらくコプロセッサを使うはず)はスレッドセーフですか?またそれは/fp:オプションによらず不変? よろすくおながいしますorz
A1: Windows 98, 2000以降はyes A4: yes
A2 コア別でしょう。たぶん。コア間共有なんて設計のほうが難しいと思うよ。 A3 コア別でしょう。たぶん。コア間共有なんて設計のほうが難しいと思うよ。
>>326 >CloseHandle((HANDLE)_beginthreadex());
その組み合わせはちょっちまずくね?
ttp://msdn.microsoft.com/ja-jp/library/cc429080.aspx にメモリリークが起きると書いてある(ちなみにやねうら本(1)にもそう書いてある)
ExitThread()を明示的に呼ばなくても、スレッド関数を抜けたら同じことのはず
なお、>326の反対(CreateThread()が返したハンドルを _endthread()で開放する)は明白に危険であろうことが上のリンク先から推測できる
(確保されていないメモリを_endthread()が解放しようとするハズ)
何のために_beginthread()〜_endthread()や_beginthreadex()〜_endthreadex()があるかというと strtol()みたいに、機能的にはマルチスレッド環境下でも動いて欲しいのだが関数仕様的にマルチスレッドと相容れないような 標準関数をマルチスレッド環境でもきちんと動くようにする目的なので(おそらくそのために内部的にスレッド局所記憶を確保している) そういう類の関数を明示的にも暗黙的にも呼び出さないと誓うならCreateThread()〜CloseHandle()で無問題
339 :
308 :2010/03/07(日) 18:19:56
スマソstortol()じゃなくて問題なのはstrtok()とかlocaltime()とかだった、
>>337 _beginthread は起動されたスレッドが終了時にハンドルのクローズを行う。
_beginthreadex は別途CloseHandleする必要がある。その代わり、
スレッドが終了していてもハンドルは有効であり、スレッドの状態を調べることができる。
ここでのリークというのはCRTの作業域のことではなくて
あくまでもスレッドを追跡するためのハンドルのこと。
>335, >336 レスdクス A1は実験的にも確認できた(イントリンシック関数が排他を含まないこと、およびxmm0とxmm1を使う関数を64スレッドで呼び出して無問題) A2はまあそう思う(ダイ写真でSIMDとコアの区別を確認できない&SIMDの数<コアの数ではマルチメディア目的に合致しない) A4についても使用予定関数について実験的に確認できた A3はちょっち謎 同一コードで記述され、同一コアで走る別スレッド(含HT)の場合どうなるのか? 同一コード条件とそうでない条件(コードをスレッド別コピーとする)とで速度比較すればいいんだろうけども コードをコピーすると分岐予測以前にトレースキャッシュ容量他の要因で速度低下するかもしれないから実験では精度良くは判断できない鴨
pthread_cond_wait状態になるまでに 結構時間かかるのですかね? 以下のようなコードを実効すると 結構頻繁に、別のスレッドがwait状態になる前に pthread_cond_signalを実効してしまうのですが 必ず、同期取るようにどうしたらいいのでしょうか thread1 { while(1){ pthread_mutex_lock(&m); pthread_cond_wait(&c, &m); pthread_mutex_unlock(&m); } } main { while(1) { pthread_mutex_lock(&m); pthread_cond_signal(&c, &m); pthread_mutex_unlock(&m); } }
どうやって確認したの?
何がしたいのかよくわからんが、 とりあえずmutex取得する前にシグナル発行してたらいかんだろう。
thread1がlockするまえにmainがlock->signalしちゃってるとかありそう
>>337-338 つーか比較するものが間違ってる
_endthread()/_endthreadex()は作られた側が(必要なら)呼び出すもので
CloseHandleは_beginthread()/_beginthreadex()呼んだ側が呼び出すもの
347 :
341 :2010/03/13(土) 23:42:54
自己解決しますた!(いや、多分、だけど Windowsのスレッドコンテキスト切替は、スレッドが走り続けている場合、どうがんばっても msオーダー周期(おそらく10 msとか20 msに1回)なので、分岐予測統計の結果がその間に十分安定する(と思われ だから分岐予測精度を上げるためにコードのコピーをスレッド別に用意しておく、みたいな神経質なことはしなくて宜しい かと、
348 :
342 :2010/03/14(日) 01:04:34
訂正 誤:分岐予測統計の結果がその間に十分安定する(と思われ 正:分岐予測統計の結果が現実的に安定している期間よりも桁違いに長い(と思われ ニホンゴ、ムズカシイデス、、
いやいやいやいや いまはコア間での話ではなかったのか?
またえらい細かいオーダーで削ってるんだなぁ。 PCのWindowsでそこまでカツカツ削っても、すぐに時代変わっちゃうと思うけどなぁ。 他のとこに力入れた方が良くね? まぁ、トレースキャッシュとか気にしてるから、何か特殊な固定環境向けのガリガリな チューニングなのかもしれないけど。 俺も低レベルは好きだから、とりあえず触ることで知識と感覚を深めたい、ってんなら 止めないけど。単にバランス感覚の欠けてるケースに見えてしまうが。違ったらすまん。
>>349 分岐予測メモリはCore i7の場合物理コアごとに持ってるからスレッドごとに物理コアを違える場合は何も悩む必要はない
問題なのはスレッドの数が物理コア数より多いとか、同一物理コア内でのHTの場合(→341の下から3行目参照)
ハッよく考えたら>348-349のロジックじゃあHTの場合が解決してねーじゃんorz
同一コア内で走るHT0とHT1は、ハードウェアレベルで演算ユニット、L1, L2キャッシュ、トレースメモリを奪い合うので
もし仮に分岐予測メモリのタグがアドレスのみから生成され、HT番号では区別されない作の場合問題になりえる
ただしまあ現実的には同じアドレスに配置された同じ条件分岐命令が
1. HT0とHT1でほぼ同時に(=分岐予測結果の平均寿命(おそらく数μsec)オーダーの時間差内に)実行されるという状況が
2. 片方は分岐、片方は非分岐で
3. 無視し得ない頻度で反復される
というケースでのみ問題だが
>>350 というわけでWindows非依存な話
>>352 いや本人がWindows7を対象にしてるって最初に言ってるから
>>342 亀だが、それは条件変数の使い方を間違えとる
いきなり無条件でcond_waitで待ってはいかん
cond_waitは、あくまで「共有条件が望む状態になっていない時」に使うものだ
cond_wait時に指定するmutexは、その「共有条件」をテストするためのものだ
でもってcond_signalやcond_broadcastは、共有条件の変更があったことを通知して、共有条件の再テストの機会を与えるものだ
なお、cond_signal, cond_broadcastの実行そのものには、mutexの取得は必要ない
JMなんかのpthread_cond_initのmanページを見て、使用例を確認すると良い
355 :
デフォルトの名無しさん :2010/03/27(土) 11:48:41
ここのコメント欄みづらいんだよね 最初の「必要以上に複雑になってる」という指摘は同意。 この記事って、バグのあるコードをだんだん直していくっていう 流れだけど、そもそもタイトルの条件変数関係ないバグだし、 修正内容も、なんか泥沼に入っていくような感じ その後のやりとは、この二人にしか分からないどうでもいいことについて、 どうでもいいやりとりしてるように見えた。
357 :
デフォルトの名無しさん :2010/03/27(土) 15:20:18
「Java並行処理プログラミング」が増刷してる
va_argsってスレッドセーフですか?
va_list を自動変数やTLBに置いていれば、va_listをスレッド間で共有しない限りは、スレッドセーフだと思うぞ。
>>360 嘘ついちゃだめ
va_listはプロセスで1つだけしか持てないから
スレッドセーフじゃないよ
362 :
デフォルトの名無しさん :2010/04/19(月) 00:34:37
ボナンザ8コア対応を16コア対応にする方法を教えて下さい。
スレッドセーフかどうかってのはcrtのソース見ないと判断付かないって認識でおkっすか?
>>364 じゃあ証明してくれよ
できないだろw?
>va_listはプロセスで1つだけしか持てない
それとスレッドセーフの話にどんな関係が?
>>365 簡単。
va_listはプロセスで複数もてるから
スレッドセーフ
すみません、spin-lockをしている間にCPUの使用率を下げる方法を知っている方はいますか? 調べてみると、rep;nop命令やSSEのpause命令をがそれに該当するように思えるのですが、 使ってみても何ら変わりませんでした。 自作のスレッドバリア関数(自作のspin_lock)を作って、 たとえば、 if(threadnum=5) sleep(10); my_barirrer(); とするとスレッド5を待っている間は5以外のCPU使用率が100%近くなってしまいます。 それに対してOpenMP使った場合では、 if(threadnum=5) sleep(10); #paragma omp barirrer だと待っている間はCPU使用率は殆ど変わりません。 ちなみに自作のspinlockは下記のような感じです。 if(thread_num == 0) { asm volatile( "Loop1:\n\t\t" "movl (%0), %%eax\n\t\t" "movl (%1), %%ebx\n\t\t" "lfence\n\t\t" "cmpl %%ebx, %%eax\n\t\t" "rep;nop\n\t\t" "jne Loop1\n\t\t" : :"r"(&lock->sync), "r"(&lock->maxthreads) :"memory","%eax","%ebx" );
>>369 方法はあるけど、物凄くマヌケで無意味だから誰もやらない。
スレッドとかの切り替えを自前で用意するとか
372 :
369 :2010/04/22(木) 09:40:25
いろいろと試してみたのですが、マヌケな方法しか思いつきませんでした。 (スピンを何回かしたら、nanosleepを使うとか) pthreadのライブラリのソースを見てみると、futexのシステムコールが呼ばれているようですね。 OpenMPで生成したスレッドの中で実行される関数間でスレッドの同期をとりたかったのと、 せっかくOpenMPを使っているから、 pthreadとか使いたくなかったので自前のspin_lockを作ってみました。 マヌケな質問をしてすみませんでした。
ヒント:スピンロックを使わない
Win32でスレッド間のイベント通知をやりたいんですが 2つのスレッドが同時にそれぞれSetEvent(), ResetEvent()を呼び出した場合の動作って定義されてるんでしょうか? やっぱりクリティカルセクションで囲ってやらないとまずいですか?
イベントオブジェクト自体の動作には問題ないけど、 使い方ミスりやすいから十分気を付けた方がいいよ。
プロのコードではイベントオブジェクトは使われない
配布したときに問題が出るからな
どんな?
無名にすれば他のプロセスと衝突することも無いし、kernel32.dllだから別にDLLも不要だし問題が思いつかないな
なんか勘違いしてんだろ
383 :
デフォルトの名無しさん :2010/05/16(日) 21:15:32
wait-freeなキューの実装を可能にするのに必要な不可分操作ってどんなんですか?
候補となる不可分操作には何があるの?
385 :
383 :2010/05/16(日) 23:57:41
>384 JAVAのConcurrentLinkedQueueだとCASをつかってるってことしか知りませんが..
スレッド間のヘルスチェックに定番な方法ってあるのでしょうか? ・マスターなスレッドAが外部変数にスレッド数分bit1を立てる ・B以降のスレッドは、自分に対応するbitを落とす ・一定時間、0じゃなかったら誰かが止まってるのでNG とかすると、sem_wait()で普段寝ている人(これはその時だけ起こせばいい?)や、 recvやselectで待ってる人の確認はできない。。
スレッドのヘルスチェックって要るのかな?プロセス間だったら必要かも知れなけど。
大事な役割を持ったスレッドが刺さってないか確認したいんじゃないの
タイムアウト指定して待ちっぱなしにならないようにするのが基本
ワーカースレッドとUIスレッド分けたとき、時間のかかる作業を ワーカースレッドがしているとき、UIスレッドはどうしているべきでしょうか 今は終わるのを待たずに終わるまでデータ変更の起こる操作を禁止しています でもそれだとウィンドウ動かせるくらいしかメリットがないので考え中です
>>391 俺は[中止]ボタンが押されるのを待つか、タイマーで定期的に終了したかどうか
チェックしてる。あとプログレスバー表示。
ボタンを禁止にしたりキャンセルを受け付けたり面倒だよな それとプログレって、量的な変化ならいいが、 手続き的な進行表示には不向きだよな
全体量がわからないやつはつらいよね \-/-\-...ってやつが好きw
経過表示なら1/n「(説明)」〜n/n「完了」でいいと思うんだ
progress_display「呼んだ?」
いや、全然呼んでないよ
399 :
デフォルトの名無しさん :2010/06/27(日) 14:54:02
>>391 おれはその処理に関連するメニューだけロック(選択不可とか無視とか)して他の操作は許可してる
処理が終わったら通知ポップアップ
処理状況なんかはモーダレスじゃないプログレスバーかステータスバー表示
400 :
デフォルトの名無しさん :2010/06/27(日) 15:01:41
>>393 でも長時間うんともすんとも言わないと不安になるからそういう場合は一秒に一ブロックぐらい進むプログレスバー繰り返してる
中止は処理スレッドに定期的に中断フラグチェックさせてプログレスバーダイアログのOnClose/OnCancelで終了フラグOn+WaitForSingleObjectさせればOK
>>401 バブルソートを題材にするとか並列化のサンプルとして適切じゃないというかフェアじゃないというか、あえてそれを選ぶのはなぜ?って話でしょう。
>何でもかんでも並列化すれば、等しく速くなるわけではない 記事の結論には同意だけど記事書いてるひとはアホ
>>403 同意だな。
並列化に向いたアルゴリズムをつかわにゃ早くならんしな。
ていうか変数shareしすぎ。
だらだらと下手糞なコードを書いて速くならねえよと喚かれてもな そんな記事にはほとんど価値がない
結局バグってたっぽいw コメントが間違ってなければだが。
記事自体は、アルゴリズムによって効率的に並列化できるとは限らないから云々んという内容なので、 記事自体が(素人にとっては)無意味だとまでは言わんが、 この人偉そうな言い方したり他人の記事に対しては重箱レベルで突っ込んだりもしてるくせに 自分の記事は内容が結構いい加減なんだよな。
そんな人は世間にはいっぱいいる
「並列処理は〜」と一般化された題材に対して、帰納法で証明しようとしているのが問題かな 「マルチスレッドに向かないアルゴリズムがある」というテーマならこの方法で十分だけど
410 :
デフォルトの名無しさん :2010/07/04(日) 00:08:29
むしろ、そうじゃない人を見たら驚く。ライターなんてゲームの販売と同じ。 品物を売るまで、記事を読ませるまでが勝負。その後や内容なんて気にしなくてよい。
ライターじゃないだろ
金とってんのか
ひとをみたらライターと思え
ゲームの販売と同じなら、クソゲー売り続けるのと名作売り続けるのじゃ全く末路が 違うことくらい分かるだろうにアホか
>>401 記事を書いている本人が明らかに知識不足で、可笑しい。
テキトーに眺めただけで、コイツはダメだって分かるレベル。
並列化したプログラムの例として、アトミックな足し算使った合計計算のコードを出すような人だからな。 何がしたいのかさっぱりわからんレベル。 ほんとにまともなマルチスレッドのプログラム書いたことあるんかと。
>アトミックな足し算使った合計計算 とりあえずPageRankみたいな巨大行列計算だと使うんじゃないかな。 並列化というより分散化したいレベルだけど。
418 :
デフォルトの名無しさん :2010/07/04(日) 22:58:48
まともに組んだことがない人の記事だな
まあそこまで批判するべきことじゃない わからないから試すのであって、わかるならする必要はない まあ公開するならそれなりに検証して見栄を張るべきだとは思うけどねw素直すぎる
MTでパフォーマンス出すには、理屈を理解する頭が無いとどうしようもない気はする
分からないから試す、にも二通りある
「何が分からないかを分かった上で試す」のか
「何が分からないかも分からないまま試す」のか
まぁ
>>401 に関しては、ほんとにチラ見しただけでバカ記事っつーか、むしろ真面目に
叩いて貰えてるだけ幸せなんじゃね?
いやマジで、俺ならこんなのに関わる気にもならんわ。
どうせバカ記事書いた本人は「めんどくせぇのに絡まれたわ」程度にしか思わねーんだろ
と思うとなぁ。
>>419 この人の並列処理関連のいろいろなブログ記事とかCodeZineの記事ね、
元々ほかの人の並列処理関連の記事の批判から始まってるんだよね。
ばかなこと書いてるやつがいるので俺が訂正してやるって、
ほんとにこういう感じなのね。
で、あの記事なんだわ。
>>421 なぜ?氏の指摘はやっぱりおおよそ的を射てる内容なのかな?
つうか着々と増え続けとる…
へえ
ほぉ
なぜ? Posted @ 2010/07/07 22:46 >スレッドの終了を、もうちょっとスマートに待てないのかなぁ?まぁ、動いてるからいいや。 全然よくありません。 Sleep(0)を入れているとはいえ、無駄なループでCPUを使用していては、まともな計測はできません。 コア数以上にスレッド数を増やしても改善していってしまうのは、これも原因なのではないですか? >おかしいと思ったらできるところまで追求する。それが職人ってもんじゃないですかねー。似非職人はヤーネー。 いくらなんでもこんなこと言いながらこれではダメでしょう。
本人に言えよ
おまえならできる
?
本人?
433 :
デフォルトの名無しさん :2010/07/08(木) 01:19:38
馬鹿が呟いているだけだから無視でいいだろ。話題にすらならん。
ヲチスレじゃないしな もう少しマシな話題ならともかく、内容がどうでもよさすぎる
最近話題がない
くだらないネタで流れるなら止まってた方がずっといい
マルチスレッドと関係ないかもしれないけど、 CPUって忙しくないときどんな状態になってるんですか? 割り込み待ち状態なんですか? それともなんらかの無限ループ状態なんですか?
忙しくなさ次第でいろいろ
>>437 ちょっと暇なときは、いっしょうけんめいだらだらしてる。
だいぶ暇なときは、夢の国へいく。
>>440 それじゃ何の説明にもなってない
つーか環境次第で千差万別だから、本気でそういう情報が必要なら仕様書を当たるといい
単に何となく興味があって聞いてみた程度なら、めんどくさいから知らなくていい
仮にx86なら、暇になったらHLTかPAUSEを仕込んでおくことが多いだろうけど、そうで
ないのもあるし、単純にHLT発行すればいいって話でもないし、そもそもぶっちゃけた話、
全く知らない奴に頭っから全部説明してらんね
halt状態の休み方も何段階もある訳だし
>ちょっと暇なときは、いっしょうけんめいだらだらしてる。 スピンロックか
445 :
350 :2010/08/17(火) 20:53:09
「マルチスレッド」の説明する時に「マルチタスク」の状態遷移持ち出す奴がいて、俺的には「?」なんですが、そういうのありなんですか?
プロセス空間が分かれていない頃の書籍でマルチタスク学んだ人なら普通じゃね?
>>445 大して難しい話じゃ無いし、基本だから知っておくべきだろう。
リアルタイムOSの「タスク」は、Unixのスレッドのようなものだったりするぞ。
>「マルチタスク」の状態遷移 て何ぞね DORMANT/WAITING/RUNNINGとか言った類類の話ならタスク単体の状態だし タスク同士の関係は非同期というのがマルチタスクの本性であるからして、 複数タスクに渡る状態など一般には規定しようがない 設計者がタスクそれぞれに明示的に同期ロジックをプログラムしたという想定で、 その詳細が明かにされた上でなら話は別だが
まあ、
>>445 は理解できなかったって言ってるんだから説明も出来ないだろう
451 :
デフォルトの名無しさん :2010/10/01(金) 17:29:29
あんまり理解できてないのでうんこみたいな質問申し訳ないんだけど、 スレッドが二つ(A,B)あって、 変数 int a にスレッドAがひたすら数字を入れて、スレッドBはひたすらその数字を読むだけの場合、 int aの書き込み・読み込み時にクリティカルセクション使う必要はある? 手元で試してみたら片方が読み込みオンリーの場合正常に動いたんよね
移植性のあるコードを書こうと思ったら必要なる。 ただハードやOS・言語・コンパイラ・ライブラリなどが想定するメモリモデル (平たく言えばマルチスレッドでメモリがどう見えるかのルール)によっては それで正しいケースもある。 具体的な回答が欲しいならpthread、Win32のスレッド、Javaや.NETくらいの くくりで質問するといいよ。
>>451 まず、書き込まれた値が化けたりせず正常に読めるか、という点については
適切にアラインされている、CPUのワードサイズ以下の値なら、まず問題ない。
Cコンパイラにおいて、「int」として扱われる値を
Cコンパイラに配置させる場合は、まず大丈夫。
ただし、スレッドAが書き換えた後にスレッドBが読み出したとき
直前の変更が適切に反映されているかどうか、については
環境依存、というか普通は保証されない。
一方通行なら問題ないでしょ
他に受け渡すデータが一切どこにも何もなくて、ただその数字1個を渡せばいいだけなら
ハード依存OKということならシングルCPUのPCは スレッドに関するほとんどの問題発生しないし正常に動くね。
読み出しで値を比較するときはちょっと考えないといけないかも
>>452 すまん、VC++で、Win32APIのCreateThread使った話だった
>>453 thx 直前の変更は特に気にしなくてもよさそう
取り扱う変数がvectorとかlistになってくるとまた違うんかな……
ひたすらスレッドAが書き込んでスレッドBが読み出してprintfするだけなら正しく見えるが、 例えば、イベントを受け取ってスレッドAが書き込もうとして、スレッドBは読み出すとき、 読み出された値はスレッドAが書き込こむ前か後かはCPUの気まぐれになりそうな気がする。 まぁそんな時はロックしなくてもスレッドAが書き込み終わったらスレッドBに読み込むように言えばいいけど
Win32での32bit読み書きはアトミックな操作だっけ?
>>461 Win32の環境じゃなくIA32とかx64の意味でじゃないの?
i386SXのように外部データバスが16bitのものはどうなるんだろ。 i386SXでマルチプロセッサ構成は見たことがないけどね。
たぶん、データが化ける可能性があると思う。 386SX以外にも、68000とか8088とかがその系統だったと思うし 今後も組み込み向けとかにそういうのが出てこないとは言い切れない。 だから、「intなら大丈夫」じゃなくて「intなら普通は大丈夫」程度。 とはいえ、組み込み向けのバス幅制限があるような環境では マルチスレッドはともかく、 マルチプロセッサ/マルチコアはまずありえないと考えて良いんじゃないかな。
そもそも、lock prefix使えないはずなので、マルチプロセッサが構成出来ない。
386SXの32ビットR/Wや8088の16ビットR/Wは、読み書きは複数サイクルかもしれないけど、 完了するまで割込まれないんじゃなかった? 仕様書見て言ってるわけじゃないけど。 同じような構成で割込まれるプロセッサもあるかもしれないけど。
32bitのアクセスがアトミックであると保証されてるのはi486以降とIntelの資料に書いてある
>>467 割り込みは確かに発生しないから単一コアのスレッドなら問題はないが、
マルチコア・CPUの場合は問題が発生する。
んでi386SXのマルチプロセッサやマルチコアは実在するの?
ハードのことわからんのに憶測で書くなよ
>>468 i386まではDMA操作なら割り込めた、CPU単体でならアトミックだったがSXでマルチプロセッサ組んだらダメだろうと思う
小数点付きのプログラムカウンタのあるCPUでも使ってるんかね
>>475 パイプラインの途中を指し示したいみたいな?
たぶん475は、全ての命令が1クロックで実行できると思ってる。
intelのは1クロックで動くんじゃないの
ワイヤードロジックをほぼ全体に使うようになったのは486から
>>467 割り込みと、トランザクションをごっちゃにしてる?
CPUの割り込みはR/Wの間に中断しないだけ。
マルチプロセッサについてはRとWが別のトランザクションなんでR/Wの間に別のプロセッサのRやWが割り込める。
この割り込みを防ぐ信号を駆動するのがインターロック命令
読む側が、変更されない変数読んでると思われて最適化されちゃうとか無いの? volatile付けなくても大丈夫?
>>482 スレッド間で共有する変数はvolatileつけておくべきだよ。
485 :
デフォルトの名無しさん :2010/10/03(日) 14:31:25
馬鹿は黙れ。CPUの基本構造も知らずにプログラム組むとか笑えない。
>>465 > とはいえ、組み込み向けのバス幅制限があるような環境では
> マルチスレッドはともかく、
> マルチプロセッサ/マルチコアはまずありえないと考えて良いんじゃないかな。
組込み マルチコア でググレばわかるように、もはや組み込みでもマルチ
コアはありえないと言える状況ではないよ。
8088やi386SXみたいな内部と外部でバス幅が違うような 石を使わざるを得ない(特殊な?)状況限定の話にそんなレスされても。
内部と外部でバス幅が違うなんて組み込みだと今時珍しくないが もしかしてそんなことも知らんのか?
ハードの事わかって書いてるわけじゃないでしょ 最適化されたときのコードの矛盾とかをハードの問題みたいに思ってるのかも
492 :
デフォルトの名無しさん :2010/10/03(日) 19:47:54
【OS】 Linux,W2K 【言語】 C 【実行環境】Cygwin(W2Kの場合) 【その他特記する事項】 以下の行列演算は高速化できるのでしょうか。 スレッドの意味も作り方もわかりません。 for(j=0;j<16;j++){ for(i=0;i<16;i++){ d1[j]^=GF[e1[j][i]]; d2[j]^=GF[e2[j][i]]; } }
>>488 >>490 「バス幅が違うような環境でマルチコアなんかないだろ?」と
>>465 には書かれているように見えるが
おまえ、日本語は苦手か?
両方を満たしたものがめずらしくもないものなら
そう反論しろよ。別個にではなく。
496 :
494 :2010/10/03(日) 20:38:18
ちょっと書き方を変える。
>>488 「組み込みにマルチコアはありえない」などとは、どこにも書かれてない。
偉そうにしてるが、幻覚でも見たのか?
>>490 「内部と外部でバス幅が違う環境などない」などとは、誰も言ってない。
偉そうにしてるが、電波でも受け取ったか?
「内部と外部でバス幅が違うような用途でも、マルチコアが採用されつつある」
と言いたいのなら、ちゃんとそう書け。
> 「組み込みにマルチコアはありえない」などとは、どこにも書かれてない。 ⇒ 「マルチプロセッサ/マルチコアはまずありえない」と書いてますが? >「内部と外部でバス幅が違う環境などない」などとは、誰も言ってない。 誰もそんなことは言ってないし、誰もそれに反論なんてしてない。 むしろ、最近は珍しくないと書いてあるんだが。 偉そうにしてるが、一体誰と戦ってるんだ? (w
>>498 インテルは言っている、素直にインテル・スレッディング・ビルディングブロックを使えと
インテルは言っている、インテルはいっている
エルシャダイスレはここですか?
だめええ!入れないでえええ!インテルいれちゃだめええええええええ!!あ?
インテルは逝ってる
スタベーションを回避する方法を教えてください。
待ち行列の先頭にいるスレッド以外は偶然入れても待ち行列の最後に並んで前の人が終わるまで待つとか
>>504 A,B,Cというセマフォを取得するときどのスレッドもA,B,Cの順でセマフォを取得する。
507 :
デフォルトの名無しさん :2010/10/13(水) 01:49:19
【OS】WindowsXP
【言語】C++,Win32
【実行環境】VisualStudio2005
かなり基本的な質問です。
スレッドを外部から終了させたい場合、どのようにすればいいのでしょうか?
あるスレッドを常に動かしていて、ユーザーがGUIプログラムを閉じた場合に、メインスレッド側からどのように命令すればいいのかわかりません。
ttp://msdn.microsoft.com/ja-jp/library/kdzttdcb%28VS.80%29.aspx ↑のようなページやググって調べると、スレッド関数側が自発的に_endthreadex関数などで終了する例はあるのですが、
終了するタイミングをスレッド関数側が知らない場合についてはあまり書かれていません。
よろしくお願いします。
終了するタイミングをスレッド関数側に教える仕組みがいくつかある
>>507 何とかしてサブスレッドに終了を伝える方法を自分で実装する。特に関数はない。
Windowsならvolatile boolかCreateEvent+SetEventでいいだろう。
いいか、お前らTerminateThreadは使うなよ!使うな!絶対に使うなよ!
kill -KILLですね、わかります。
TerminateThread = ハングしろ に近いからねぇ .Netとかだとそもそも抹消されてるが。Suspendも割と個人的に怖いな
TerminateThreadに頼ったプログラムは死んでいいけど、 バグがあってサブスレッドが応答しなくなった時の万が一のためにTerminateThreadするのは いーんでないの
つーかスレッドの終了待ちでWaitFor*Objectしてタイムアウトしたら TerminateThreadってのは普通だろ
そりはバグなので速やかにアプリケーションを終了すべきでは? 少なくとも普通じゃない。
>>510 別に使っても問題ないよ。
DllMainのデタッチスレッドさえちゃんと実装されていれば何も問題はない。
Vistaより前がターゲットに入るなら「何も問題ない」は無いわ DllMainがどう頑張ろうと関係無い
>>516 DllMainはコールバックされないってちゃんと書いてあるのにどういうコードを書くつもりなのか聞きたい
TerminateThreadするくらいならExitProcessで止めを刺す。
TerminateThreadなんて使う必要性あるの?
サブスレッドの確保したメモリとかソケットとかDB接続とかその他もろもろのハンドル はどうするつもりだよ。 あとミューテックスをロックしたまま暴走した場合とか開放されるんだっけ? 問題ありすぎ
printfはどういうレベルでスレッドセーフじゃないんでしょうか
間違えた、sprintfです
書込み先のことかな?
処理系によるんじゃないでしょうか
MT-Safe ってどういう意味?
複数のスレッドで安全という意味
>>527 POSIXというか、ぶっちゃけLinuxの標準ライブラリstdioでならどうでしょうか。
ここまで範囲限定したらスレチになんのかな?
POSIXのstdioで _unlocked が付いてないものはスレッドセーフです
つまりprintfはスレッドセーフってことか。ありがとう!
関数がってことで、使い方間違えると...
まぁ想像するだけでもprintfは外部に出力するからロックとか色々してるのは分かる printfしたらバグが起こらなくなったとかで原因がスレッド絡みとかよくある んでprintfで起こらなくなるから放置とかマジ勘弁してくださいorz
スレッドセーフなメモリの読み書きについて勉強しているのですが、情報が少なく捗りません。 メモリへの同時アクセスによるデータ破壊は、書き込み時にのみ起こると認識しているのですが、正しいでしょうか? ・二つのスレッドが一つの変数を書き換えるとき →データが破壊される場合がある。 ・一つのスレッドが一つの変数を書き換え、別のスレッドがその変数を読み込むとき →書き込みは問題なく行われる。 →読み込みは、書き換え途中のデータを読み込む場合がある。 ・二つのスレッドが一つの変数を読み込むとき →問題なし。
書き込まないものを読み込むことにどんな意味があるのだろうか
const 定数ですね
ありがとうございます。理解が深まりました。
>>535 > ・二つのスレッドが一つの変数を書き換えるとき
> →データが破壊される場合がある。
データの破壊とは何ぞや?単に後から書いたデータが残る。それだけの話。
それぞれの書き込みがアトミックならね。 32ビットマシンで64ビットの書き込みとか、アトミックでない場合、破壊が起こるかもしれない。
>>540 配列だって、立派な配列変数だぜ。
文字列型変数もあるしな。
543 :
540 :2010/12/24(金) 15:52:35
そうだった、最近のデータはでかいんだな。 組み込み系のスレ見た後だったから頭がアセンブラレベルになってた。 失礼。 俺はどっちにしてもミューテックスかクリティカルセクションで排他しておくけど。
同時アクセス時の挙動なんてCPUの仕様次第だろ 同時読込なら安全なんて確証は無い
545 :
デフォルトの名無しさん :2010/12/24(金) 17:20:04
データが小さければ読み書きのキャッシュ問題とか無視できるが、 今はふつうに扱う標準データが大きいからなあ。プログラミングも大変だ。
アホ発見
同時読込なら安全なんて確証は無い・・・ ということは同じ関数を同時に実行するとまずい場合があるってことか 同じ関数を同時に実行すると同じ命令列を同時に読込むことになるもんな
言語仕様じゃなくハードウェア仕様だと理解してればいい 大丈夫かどうかを言語仕様で調べても守備範囲外のことで規定されてないから無駄
いや失礼、言語仕様で規定されてる物もあるか
550 :
デフォルトの名無しさん :2010/12/26(日) 16:17:56
printfがスレッドセーフじゃないのはわかるけど どうしてsprintfがスレッドセーフではないのはなぜ?
>>550 内部にスタテックバッファーを持ってるかも。
>>551 まじか・・・だらしのないやつだなsprintfも・・・
おまえが使ってるライブラリを実装したところに聞けよ
sprintfがスレッドアンセーフってのはどこ情報?
なるほど 確かに
それ英語版見たらスレッドセーフなんてどこにも書いてないぞ・・・ > writefln() improves on printf() by being type-aware and type-safe: 誤訳じゃないのか
559 :
デフォルトの名無しさん :2010/12/27(月) 11:09:50
へえ
探しても「セーフだろう」「たぶんセーフ」ばっかりしか出てこない むずむずするなぁ
過去スレ全部はみれなかったんだけど、マルチスレッド関連の良書をまとめてみる。 この他にこれがいいとかあったり、これ駄目とかあったら教えて。 [一般] 並行コンピューティング技法 ―実践マルチコア/マルチスレッドプログラミング The Art of Multiprocessor Programming 並行プログラミングの原理から実践まで 増補改訂版 Java言語で学ぶデザインパターン入門 マルチスレッド編 [java] Javaスレッドプログラミング―並列オブジェクト指向プログラミングの設計原理 (OO SELECTION) Concurrency: State Models and Java Programs 2edition Java並行処理プログラミング ―その「基盤」と「最新API」を究める [windows] Win32 マルチスレッド プログラミング Advanced Windows 第5版 上 Advanced Windows 第5版 下 [Unix] POSIXスレッドプログラミング
[C++] インテルスレッディング・ビルディング・ブロック 主にこのライブラリの使い方だが、 他にもスレッド管理の考え方が載ってる。まぁオープンソースなので見れるのだけど
ありがとうございます。C++の良書をあまり知らないので助かります。
concurrent hashmapのC++実装って なんでないの?
>>566 並列mapでいいから実装ないの?
C++って並列コンテナないから何もできないよね
>>567 キミが作るだろうと思って残しておいた。
C/C++はアセンブラと高級言語の間みたいな位置だからな 言語そのものを作るとか、OSを作るとか、リソースの厳しい組み込み系で作るとか、 そういう用途じゃないなら別に強力な言語ではない ネイティブのCPUの挙動を理解しないとC/C++の有用性は半減すると思われ
すみません、spin-lockをしている間にCPUの使用率を下げる方法を知っている方はいますか? 調べてみると、rep;nop命令やSSEのpause命令をがそれに該当するように思えるのですが、 使ってみても何ら変わりませんでした。 スピンロックつかっわないとは思うんだけど。 自作のスレッドバリア関数(自作のspin_lock)を作って、 たとえば、 if(threadnum=5) sleep(10); my_barirrer(); とするとスレッド5を待っている間は5以外のCPU使用率が100%近くなってしまいます。 それに対してOpenMP使った場合では、 if(threadnum=5) sleep(10); #paragma omp barirrer だと待っている間はCPU使用率は殆ど変わりません。 ちなみに自作のspinlockは下記のような感じです。 if(thread_num == 0) { asm volatile( "Loop1:\n\t\t" "movl (%0), %%eax\n\t\t" "movl (%1), %%ebx\n\t\t" "lfence\n\t\t" "cmpl %%ebx, %%eax\n\t\t" "rep;nop\n\t\t" "jne Loop1\n\t\t" : :"r"(&lock->sync), "r"(&lock->maxthreads) :"memory","%eax","%ebx" ); というか、これって間抜けですかね?
自前でタスク切換えみたいなことするしか
割り込みでしか切り替わらないコードで使用率下げたいというのが
さむいな(´・ω・`)
寒稲
>>571 CPU使用率が100%じゃないロックなんて、スピンロックとは認めない。
そもそも100%じゃないってことはコンテキストスイッチしてるってことになるでしょ? 何のためのスピンロックなのよあり得ない。
スリープロックのループもスピン扱いすることもあるから何とも
ちょっと聞いていい? 以下のコードでnotifyAllされたらどうなるのって質問 void A() synchronized(Lock){ if(List.size() == 0){ try{ Lock.wait(); }(Exception e){} } //以下処理続く } } このコードで複数のスレッドが待ち状態だったらnotifyAllとき再度Lockを取りに行ってくれるの? もし、そうだったとしたら。 結局はnotifyで1つのスレッドのみ動かすってのと同じことになるの? それとも再起処理的に以下のようにしなきゃだめ? void A() synchronized(Lock){ if(List.size() == 0){ try{ Lock.wait(); }(Exception e){} A(); ←ここでさらに再帰的に同じメソッドを呼び出す } //以下処理続く } } おしえてエロイひと。。。
>>582 notifyAll を呼ぶと、wait してたスレッドはすべて起きて、 Lock を取りに行く
どうせみんなすぐには取れないから Lock 待ち状態になるが、すでに wait からは外れてるので、 Lock を取れた順にすべてのスレッドが動き出す
notify の場合は、wait してたスレッドのうちひとつだけが起きて Lock を取りに行く
他のスレッドは、その後 Lock が空いても、眠ったまま起きない
wait はふつう再帰じゃなくて while にする
synchronized (Lock) {
while (List.size() == 0) {
Lock.wait();
}
}
waitは、notifyされてなくても間違って起きることがあるらしいので、このように書くべきこととされている
>notifyAll を呼ぶと、wait してたスレッドはすべて起きて、 Lock を取りに行く
ということはnotifyAllでそのまま下に処理が流れていくんじゃなくて
再度 synchronized(Lock){ ←この部分に処理が戻ってくるイメージなんですかね?
別のメソッド内の以下のようなコードでnotifyAllをかけようと思ってたんだけど、
ちゃんとnumの個数分以上のスレッドは再度、wait状態に入ってくれるのか心配でした
for(int i = 0 ; i < num ; i++){
List.add(object);
}
Lock.notifyAll();
それと。
while (List.size() == 0) {
Lock.wait();
}
これしなきゃいけないんですね。Javadoc見てきました。
>>583 ありがとー。
>>584 synchronized のところまで戻るわけじゃなく、synchronized の中にいるまま、 wait のところで、
Lock をいったん解放、おやすみなサイして、起きたら元通りに取りにいく
wait は synchronized の中でありながら Lock を手放している特殊な場所
notifyAll を呼んだ側のスレッドは、notifyAll を呼んだあとそのまま下に流れていく
というのも、notifyAll を呼んだ時点では Lock は notifyAll 側のスレッドが握ってるので (synchronized 中のはず)、
wait 側のスレッドは起きるけれども、Lock を取れない
notifyAll 側が synchronized から抜けるなりして Lock を解放すると、wait 側が Lock を取って動き出せるようになる
質問です CreateThreadで複数のスレッドを作ったときに渡したパラメータは スレッドごとに別々のものを渡してもいずれ同じものに書き換えられてしまうと思うんですけど これをスレッドごとに別々のままにしてやるにはどうしたらいいのでしょうか VCなら__declspec(thread)をつけるとTLSが使えると読んだのですが これをCreateThreadに渡すThreadProcのどこで使えばいいのかわかりません
>いずれ同じものに書き換えられてしまう そういうことをやってるだけでしょ
>>586 お前がやってんのは
int a;
int* b = &a;
int* c = &a;
int* d = &a;
のb,c,dが別々のものと言ってるのと同じだろ
あーなるほど、同じ場所(=ポイント先)を渡して「別々のもの」と言い張っているのか。
forkってスレッドセーフ?
別のポインタ渡したつもりで同じものを渡していたことに気づいて悲しくなりました お手数おかけしました
593 :
デフォルトの名無しさん :2011/06/23(木) 08:39:51.24
スレッドって、毎秒ごとに数百回の開始と終了を繰り返すような使い方は正しいの? それとも、必要な時だけスレを立てる使い方じゃなくて、 スレは基本的に立てっぱにしといて、用がある時にメッセージ等を送るという使い方をすべき?
スレッドの開始はそれなりにコストの大きい処理だから スレッドプールにするのが正解
なるほど。直観的じゃないのな。
用途によるよ。一度スレッドを起動したら数十秒は戻ってこないならプールしなくても大差ない。
593の前提と変わってるじゃんか
>>593 同時に起動できるスレッドの数ってそんなに多くないしな。
32bit、Windowsだと2000個くらい(スタックサイズ標準の場合)
スレッドの生成は5ミリ秒くらいのオーバーヘッドあるだろ。
数百回やるなんて頭おかしい
>>598 今時32ビット縛りなんて考える必要なくね?
5msec!
なにそのみずほ銀行
ミリ秒はつらいな・・・ と思ったけど16ビット機なら仕方ないか。
手元の環境だと、threadの生成と実行開始のどちらも0.1[ms]すら掛からないね:)
XPからスレッド生成が凄く速くなった記憶がある
じゃあ0.1msでスレッド生成するコード晒してみろよ
Win32のCRTにある_beginthread。 生成は0.1[ms]未満、実行開始はコンパイラかライブラリに依存で0.1[ms]台からに訂正。 #include <Windows.h> #include <stdio.h> #include <process.h> struct perf {LARGE_INTEGER freq;LARGE_INTEGER t0;};void __cdecl thread(void * pArg){perf *pperf;LARGE_INTEGER t1, d;QueryPerformanceCounter(&t1);pperf = (perf *)pArg;printf("thread: %I64d\n",t1.QuadPart-pperf->t0.QuadPart);}int main(){ LARGE_INTEGER f={0}, t0, t1, d;perf perf;QueryPerformanceFrequency(&f);printf( "freq: %I64d\n", f.QuadPart);perf.freq = f;QueryPerformanceCounter(&t0);perf.t0 = t0;_beginthread(thread, 0, &perf);QueryPerformanceCounter(&t1);printf( "main: %I64d\n", t1.QuadPart-t0.QuadPart);Sleep(1000);return 0;}
>>606 5764ticks/272758=2.1ms。
一桁違ってないか?どんだけ速いマシン使ってんの
608 :
607 :2011/06/25(土) 23:17:06.14
訂正。
誤:5764ticks/272758=2.1ms
正:5764ticks/2727568=2.1ms
処理のスループットが問題なんだからJOINの時間も入れよーぜ。
あと、
>>606 はmainが先に終わると不正メモリアクセスになる糞コード
C#だけど2マイクロ秒くらいだよ。 var sw = new System.Diagnostics.Stopwatch(); sw.Start(); for (var i = 0; i < 1000; i++) {new Thread(F);} decimal time = (decimal)sw.ElapsedTicks / System.Diagnostics.Stopwatch.Frequency; Console.WriteLine("{0} [ms]", time / 1000 * 1000);
∩_ 〈〈〈 ヽ 〈⊃ } ∩___∩ | | | ノ ヽ ! ! / ● ● | / | ( _●_) ミ/ こいつ最高にアホ 彡、 |∪| / / __ ヽノ / (___) /
>>607 >>608 Core i7 2600K 3.4[GHz] HTT無効, Windows 7 X64 SP1, Visual C++ 2010 Express
>mainが先に終わると不正メモリアクセスになる糞コード
大丈夫だ、問題ない。
>>609 thread poolだから略。
>mainが先に終わると不正メモリアクセスになる糞コード こういうことを平気で書いちゃう人もいるんだな。笑える。
具体的に反論できない奴のテンプレート的反応で笑える。
>>611 Xeon E5506 2.13GHzだが0.46msだった。0.1msには及ばない。
>thread poolだから略。
Threadはスレッドプーリングされない。単にStartし忘れているだけ
node.jsの説明見ているとシングルスレッドなので万歳!みたいな記事が多く混乱してみる
あれは 『マルチスレッドやマルチプロセスではC10Kに対応できなくね? 俺良い事思い付いた。シングルスレッドでイベントドリブンにしたら良いんじゃね。』 という発想だから、 『あー、でもマルチコアマシンではシングルスレッドだと性能出なくね? 結局ロードバランサとか必須だわな。』 みたいな話をすると、そもそも何でマルチスレッドを否定していたのかという 自己矛盾に陥るので、わざとスルーしているのかもね。ちょっと分かり辛いよね。
C10Kが騒がれてたのはもう10年くらい前の話で、 その頃は1CPUでシングルコアのマシンが殆どだったしね
リクエスト来る事にスレッド作成してた今までが異常すぎ C10K問題で破綻するのは今でも一緒ですわい
>>614 >Threadはスレッドプーリングされない。単にStartし忘れているだけ
ouch
C#、試してみたら遅すぎた。
Cの4~20倍くらい掛かっている。
>遅すぎた 0.1msの20倍は2msだろ。 50スレッド生成しても0.1秒、全く問題ないような
Unix屋なんでWindowsは全く詳しくないけど スレッド数をむやみやたらを増やしてもオーバーヘッドが多くなるだけでいいことなんてないのでは? それよりスレッドプールを使った方が管理も簡単だと思うんだけど、Winの開発環境にはもしかしたら スレッドプールライブラリーみたいなのがなくて自分で仕組みを作らなきゃ駄目なのかい
スレッドは設計?をよう考えないとハマるだろうに
>>621 UNIXでよく使われるものはWindowsにもある
と考えてまず間違いない
スレッドのメリットはスループット性能だけではないのだが。
メモリ空間が共通なのはデメリットだよね?
共通じゃないのが欲しければfork→execでいいんじゃね。
メモリ空間共通のデメリットって、Cでメモリ破壊の危険性を排除できない ぐらいしか思いつかないんだが。
・メモリ共有だと、プロセスが落ちたら皆落ちる ・NUMAではメモリ上のデータは分散していた方が良いよね? ・別プロセスなら別ノードにも移せるので自由度が高い ・セキュリティ(他の実行単位からデータが見えない) 等々
仕事で4Gの空間じゃ足りないってことがあった 64bitならしらねw
NUMAは違うだろ どこから割り当てるかは別にプロセス分けなくてもできる
メモリ空間が共通なのはメリットだろう常考
プログラムは常に死ぬ可能性がある という前提に立つと、 メモリ空間の共有はデメリットだよな
メリットもデメリットもある
>>632 >プログラムは常に死ぬ可能性がある という前提に立つと、
なんという時代遅れのやつ
スレッド蹴るかプロセス上げるかは、利用場面での損得勘定で決まることだから、 状況想定もなしにメリットデメリットを語ってもナンセンスすぎてなあ…
>>635 マルチスレッドで得られるメリットは基本的にパフォーマンスのみ。
マルチプロセスで得られるメリットはマルチスレッドで実現不能なことがほとんど。
ある特徴が長所なのか短所なのかは目的次第(この話に限らない一般論) パフォーマンスいらないならマルチスレッドなんてしないだろ
処理中にUIが固まらないようにするためのマルチスレッドは よく使用されるが、それをパフォーマンス目的とは言わないだろう
パフォーマンスだけがメリットだとしても、パフォーマンスのメリットは計り知れない からな クラしか見てない奴はパフォーマンス需要は頭打ちと思ってるかもしれんが、鯖は逆に クラウド化でクラの負担も全部引き受ける路線だから、パフォーマンスが非常に厳しく 求められるようになってる訳だし、鯖向けソフトウェアはパフォーマンス一つでシェア が取れる例も全く珍しくないしな
×クラウド化で ○クラウド化とか含めて
>>638 例が適切ではアリマセンネー
UIを固めない = 操作者を待たせない = 操作者も含めたシステム全体のパフォーマンス向上、
という図式が成立するとも言う
パフォーマンス向上以外のマルチスレッド利用としては、
非同期事象を取りこぼさずに受けるため、というのが挙げられると思うが、
それとて取りこぼさずに済むためのハードウェアの速度要件もしくはCPU時間消費の低減につながるため
結果的にパフォーマンス向上と言えなくもないという、
>>641 副次的な効果を目的に持ってこないほうがいい。
UIを固めないと中断が実現できたり、操作者のわかりやすさに繋がるんだよ。
それはパフォーマンス向上ではなく、別のことが目的だろう。
644 :
デフォルトの名無しさん :2011/08/14(日) 13:58:19.75
>>643 例えばIDEがエディタを固まらせないでバックグラウンドでソースを解析するのは
>操作者も含めたシステム全体のパフォーマンス向上、
になるんじゃないの?
>>644 よく読めよ。
>>638 が噛みついたのは「処理スレッドをUIと別にするのがパフォーマンス目的か?」
じゃなくて、
「マルチスレッドは必ずパフォーマンスが目的と言えるのか?」だろ。んなこたーない
うーん・・ ことプログラミングの文脈に関する限りはユーザーリスポンシビリティやユーザーエクスペリエンス はパフォーマンスの一部と解釈することはあまり無いんじゃないかな?
「パフォーマンスの向上」が何を意味するのか、が決まらないと無意味な議論だな その点に限れば、主観以外の論拠が出てこない(実際出てない)から、終着点なんか 無いぞ 元々MTのメリットという話題だったが、技術的に何の参考にもならん話だしどうでも いいんだが
意味を定義しても無駄な議論だけどね:b
652 :
デフォルトの名無しさん :2011/09/09(金) 19:42:55.52
C#のマルチスレッドのプログラミングです。 変数がいくつかある。例えばこんな感じ。 int A; int B; ・ ・ int Z; で、スレッド@で定期的にA〜Zの変数の値を更新している。 スレッドAからこれら変数を読みたいのだが、必ずA〜Zまで全部更新された状態で読みたい。 (つまりスレ@が更新処理中に読みに行くのはアウトってこと。) 優先度が高いのはスレ@です。 どうやれば“スマート”なんでしょう? 変数を更新している間スレ@以外の実行を止めるような仕掛けがあるんじゃないかと思って探したんだけど無さそうだね。
654 :
デフォルトの名無しさん :2011/09/09(金) 20:10:35.64
>>652 途中で読まれてはいけない更新の開始から最後までロックする。
ロックが長時間にわたる可能性がある場合はSystem.Threading.Mutex.WaitOneで
タイムアウトさせる。
1以外は読むだけなんだろ? そりゃ System.Threading.ReaderWriterLock だろ
657 :
デフォルトの名無しさん :2011/09/12(月) 00:26:16.03
中途半端な状態で読むのがアウトってだけだったら、一つのクラスにA〜Zの変数をまとめておいて 更新時には丸ごと新しいインスタンスに差し替えてしまえばロックいらないよ
RCUのめんどいところは古い情報をいつ削除するか
C#での話だからGC任せでok あと、インスタンスへの参照を保持する変数にはvolatileを付けとけよ。
この使い方だと実はつけなくても大丈夫だけどな。 つけとく方がいいけど。
クライアントが古い方への参照を持ち続けていてはまると予想。
>661 の他にも、「新インスタンス上の変数A??Zへの書き込み」と 「共有変数を新インスタンスへの参照で更新」がリオーダーされないようにする必要がある。
.NET Framework 2.0以降(CLR2.0以降)のメモリモデルでは、 書き込み順をリオーダできないというルールがあるため、それは起こらない。
>>663 一般の変数に関しては、そんな規定は仕様書の何処にもない。
は?
コンパイラが順序通りに書き込んでもCPUがそのように 振る舞うわけねーだろ
メモリモデルの意味も分かってない馬鹿ばかり。
ちなみに読み込みは順序換えが許されている。 一般的には読み込み順序の問題でvolatileが必要になるんだが、 今回のような処理では、参照変数より先に参照先を読むことが不可能なため、 volatileがなくても実は問題が発生しない。 もちろん読み込みの挿入が許可されてないってのも重要なんだが。 まあ普通はvolatileつけるでOK。
>>669 いや、だから読み書きともに順序替えが許されてるんだってば
>>669 つけなくて大丈夫ってことは無いよ
なにか別のパターンと勘違いしてないか?
つけなきゃだめってのは、何を見て言ってるの? CLR2.0のメモリモデルでは書き込み順序換えは許可されてない、 かつ読み込みを複数回に分ける事も許可されてない、 したがって今回のような処理では実質的にvolatileは不要。 このことはMSDNマガジンにも書かれてる内容。
>>670 書き込み順序換えは出来ないとはっきり書かれてる。
>>673 どこに?
CLIの仕様書にはどこにもそんなことは書かれてないが。
>>672 それはあんたがMSDNの記事を誤読してるだけだろ。
>>674 だから最初からCLR2のメモリモデルではと言っとろうに
C# よく分かんないけど、変数をまとめたクラス class Vars { int a, b, c, ...; static Vars instance; } があって、更新側 Vars v = new Vars(); v.a = aaa; // 1 v.b = bbb; // 2 v.c = ccc; // 3 ... Vars.instance = v; // 4 これで 1 〜 3 の順番が入れ替わるのは許せるけど、 1 〜 3 と 4 の順番が入れ替わるのってありなの? まじ???
679 :
678 :2011/09/15(木) 12:21:02.84
続き。volatile の必要性については、参照側 int prevA = 0; while (true) { Vars v = Vars.instance; if (v.a != prevA) { doSomething(v); prevA = v.a; } } とすると、参照側の Vars.instance のアクセスがキャッシュされるから、 Vars.instance は volatile じゃないと駄目ってことでしょ。 Vars.instance を直接アクセスせずに getter を介してれば volatile は不要、かな?
>>679 不要。
読み取りを削除出来るのは、同一ロケーションからの隣接した読み取りのみ。
よって読み取りが削除されることはない。
>>678 ECMAのメモリモデルではあり得るが、
CLR2のメモリモデルでは起こらない。
>>680 おっと、もう少し正確には、読み取りが丸ごと無くなってしまうような事はない。
どうでもええけどえらそーに言ってたやつらが急に黙りこくってて笑えるぞ
>>677 それって、Xbox360のXNAとかWindowsPhoneとかでも同じなのかな。
IA-64版のメモリモデルをx86版とほぼ同じになるように修正したのは
ビジネス的な判断としてはアリかもしれんが、
PowerPCやarmでも同じようにするのはオーバーヘッドが大きすぎると思うんだが。
実行環境(.NET Framework)の話とC#などの言語の話がごっちゃになってる気がする。 .NET Frameworkのモデルでは書き込み順が入れ替わることはないが、 その前のコンパイラの段階で x = 1; y = 2;が逆転することはある。
ねーよ。 何のために変わるんだよ。
まあCLRのメモリモデルを頼りにしたければ、MSILで書けってこった。
メモリモデルに反するコンパイルを行うコンパイラがどこにあんだよ。
\ここにいるぞ!/
ヒュー!
ハンドコンパイラ、自由にコードを作成できる
最近のコンパイラは最適化もしなくなったのか
「最適化」を「何でもアリ」と勘違いしているヒトが居る模様
実際問題、最近のマルチスレッドを前提とした中間言語処理系では、 昔みたいな静的コンパイル時の大胆な最適化は行わない。 というか、実行環境のCPUが想定できないので、あまり意味もない。
もっとも、可能性で言えばECMA仕様準拠のコンパイラならありえなくはない。 MSのコンパイラならあり得ない。 でも多分、ECMA仕様準拠のコンパイラでもそんなことはやらない気がする。
それこそ言語仕様次第でしょ。 たとえばCプログラムが、逐次一貫性メモリモデルに沿ったプロセッサで動く実行コードに コンパイルされるとして、じゃあ何が保証されるかというとCの言語仕様の範囲内でしかない。 書き込み順を入れ替えても、Cコンパイラとしては正しい。
だから最初から特定の処理系の話だよね。
そして言語仕様だけでは定義されてない範囲ってものがある。 C言語仕様だけじゃマルチスレッドにおいて何もできない。
結局、>678の質問の答えはどうなん? CLRの仕様から答えは決まるのか、 それともC#も仕様で決まるのか?
>699 >698が言ってる通り、C#の仕様では1-4の実行順序は規定されていない。 よって、リオーダーは起こりうる。
C/C++の仕様だと、;等のシーケンスポイントの前後での入れ替えは 起こらないことが規定されてるけどな。 機械語の書き込み順が、現れた順番で行われるかどうか、という点には 何も規定されていない。JVMやCLR等はそういう点にも言及されていると。
それはCプログラムの意味(抽象機械上での振る舞い)定義でしかないよ。 意味が変わらなければ入れ替えは許される。 (そうでないと、ループ不変式移動すらできない) 問題は、Cプログラムの意味定義は実行の流れがひとつという前提でなされていること。
ついでに機械語命令の実行順は、プロセッサの仕様で規定されている。 もちろん未規定な部分もあるけどね。
???
>問題は、Cプログラムの意味定義は実行の流れがひとつという前提でなされていること。 C#の言語仕様では、別スレッド等ではなく突然実行が複数になったり入れ替わったりすることを許しているわけ? >ついでに機械語命令の実行順は、プロセッサの仕様で規定されている。 CLRでは規定されてないとでも?
さっきから暴れてる方、 >>698が言ってる通り、C#の仕様では1-4の実行順序は規定されていない。 や >意味が変わらなければ入れ替えは許される。 の出展を示してくれませんかね。 それぞれ、C#の言語仕様とCの言語仕様の、どの部分で言及されているのか。 でなければ、ただの脳内妄想と区別がつきませんので。
その通りだと思うが出典だぞ
C#言語仕様の範囲では、 C#言語仕様の 3.10 実行順序 および 10.5.3 Volatile フィールド で規定されてる。 でMSの.NET Frameworkの実装としては、何度か出てるCLRの仕様に則っている。
コンパイラが実行順序かえたら駄目だろ
710 :
708 :2011/09/20(火) 09:28:06.57
レベルひくっ
○____ .|| | .|| ● | .|| | .|| ̄ ̄ ̄ ̄ .|| 君が代は ∧__,,∧|| 千代に八千代に ( `・ω・|| さざれ石の巌となりて ヽ つ0 こけのむすまで し―-J
>>708 C#言語仕様もCLRの仕様も、またECMAのCLI仕様においても、
全部「命令のリオーダーが許されるか否か」の視点でしか
記述されてないんだよね。
例えばCLR2.0においては、同一スレッド内の書き込みの順序は
入れ替えられないとされてるようだけど、実行環境がx86であれば
それは単に「コンパイラがプログラムを機械語に落としこむときに
書き込み命令の発行順を入れ替えない」とするだけで実現可能。
x86 CPUのメモリモデルは非常に強いので、アウトオブオーダー実行などによって、
ある書き込みが先行する書き込みより先にglobally visibleになることは認められていない。
714 :
713 :2011/09/23(金) 11:35:46.25
でも、PowerPCやarmでは事情が違ってくる。 これらのCPUのメモリモデルはx86よりもずっと緩いので、 単に「コンパイラが書き込みの順序を入れ替えない」とするだけだと、 CPUによるリオーダーによって「他スレッドからは書き込み順が 入れ替わったように見える」ことが起こりうる。 一方で、このようなCPUによるリオーダーまでも防ごうとすると、 ほとんどの書き込み命令の間にメモリバリア命令を挟まなきゃ ならなくなる。当然、パフォーマンスの低下はとてつもない。 .NETのメモリモデルって、x86のことしか考えてないように見えるんだよね。 JavaやC++11のメモリモデルは、そういう「リオーダー禁止」とかの 直接的視点ではなく、もっとメタなレベルで「ある書き込みが ある読み込みからはvisibleか否か」を定義してるので、 x86以外のアーキテクチャでも実装しやすくなっている。 今後、マルチコアなWindowsPhoneが出てきたときに いろいろ酷いことになったりしなきゃいいが。
実際にitanium版とかあるわけで、実用上なんとかなるレベルだったんじゃないの?
あとCLIとかのメモリモデルもリオーダはメモリの可視性を含めた話だよ。 キャッシュの影響で、実質的に順序が変わったように見える話とかも出てきてるんだから。 特にECMAの仕様はかなりjavaに近いと思うが。 ていうかほとんどjavaと変わらんような。
書き込み毎にメモリバリアいるんじゃないかってのは俺も疑問無くはないんだけど、 多くのCPUではこのルールを守るのは大してペナルティはないというのも読んだことがあって、 実際のとこはよく分からない。
何が言いたいのかわからんなあ
ペリフェラルいじるときは エイエイオー しまくりだ
CLRなんて作らないから、どうでも良い。
>>715 Itaniumで.NETアプリを動かすのって、基本的には
x86のWindowsサーバー上のアプリをそのまま持っていきたい
ってニーズがほとんどだろうから、その場合はパフォーマンスより先に
互換性確保のほうが最大限に重視されるだろうね。
C++0xとCLRとJavaのメモリモデルの違いとか考えたこともない話だわ マルチスレッドに詳しいひとは普段どんな仕事してるんだろ
排他に必要なメモリバリア類をライブラリだかCLRだかVMだかがやるんじゃないの。 そこを超えて踏み込む(=排他をケチる)とメモリモデルの違いが表面化するとか? 俺の持論:volatileで十分w
volatileの言語仕様知らないだろw
volatileを信用してると痛い目合うコンパイラもあるぞ
会う
コンパイラからバールのような物が飛んでくるのですね
perlのようなものか
>>716 ECMA-335はvolatile変数についてrelease-acquireバリアは要求してるけど、
sequential consistencyは要求してないように見える。12.6.7には
> a conforming implementation is not required to provide a single total ordering
> of volatile writes as seen from all threads of execution.
とも書いてるし。
730 :
729 :2011/09/24(土) 18:20:59.69
>>716 だから、ECMA-335において、たとえば以下のようなコードでは
volatile int a = 0;
volatile int b = 0;
Thread1: { a = 1; int r1 = b; }
Thread2: { b = 1; int r2 = a; }
r1 == 0 && r2 == 0 という結果も許されるんじゃないかな。
一方で、JavaのvolatileやC++11のstd::atomicはこういう結果を許さない。
731 :
デフォルトの名無しさん :2011/09/24(土) 19:22:11.48
.NETではInterlocked使うんだよ
メモリバリアとアクセス競合ごっちゃになってないか?
javaってこれのせいでvolatile遅いんじゃねーの?
734 :
デフォルトの名無しさん :2011/09/25(日) 00:21:16.82
Javaって誕生当初はロックのコストが無視できるくらいVM遅かったの? コレクションが全部同期とか頭おかしいよね
735 :
デフォルトの名無しさん :2011/09/25(日) 00:25:40.60
遅かった
複数リクエストが並行してバンバン来るservletやjspがその上で動いてたもんだから大変
ハードディスクが一つしかない環境だと ファイルアクセススレッドを何本走らせても結局ハードディスクにアクセスしてるのは常に一つだから 二本目以後は意味ないですか?
そんなことはない。
シークが増えて、余計に遅くなるという意味なら有る
CPUから見ればI/Oは超遅いから無意味、と予想するけど OSやHDDのキャッシュでかなり違うのかもしれない 結局環境依存だしやってみて実測するしかないっていうね
>>738 >>740 シークを待っている間に別の処理を行える事で、
早くなる可能性もある。どっちに転ぶかは仕様
次第なんで、それだけの話じゃわからない。
確実に言えるのは「早くなる場合と、遅くなる場合と、変わらない場合がある」って事だけだ。
S-ATAて仕様上はコマンド並び替えとかでシーク減るとか無かったけ?
期待するだけ空しい
NCQをまともに機能させるのは大変なことだお( ^ω^)
FFのリークが酷過ぎ
メモリバリアとか難しすぎて頭おかしくなりそう atomic_int a = 0, b = 0; //thread1 a.store_acquire(1); int x = b.load_release(); //thread2 b.store_acquire(1); int y = a.load_release(); これでx == 0 && y == 0が真になることがあるという話なんだけど頭の中でどう考えてもならない いったいどういうカラクリでx,yが同時に0になるの?
>>747 正しくはstore_releaseとload_acquireね。
store & acquire とか、load & release とかいう組み合わせはない。
>>747 他のスレッドに値が反映されるまでラグがあると考えればいいよ
>>747 atomic_int a = 0, b = 0;
//thread1
a.store_release(1);
int x = b.load_acquire();
//thread2
b.store_release(1);
int y = a.load_acquire();
だとすると、
load_acquire()はstore_release()の前に移動できる。
そういやなんで皆ロックの速さに拘るの? スレッド全体の処理量に対してロックが必要なのは極僅かでしょ。
いやロックの話じゃなくてアトミック操作の話
排他ロックしたら負け
volatileで十分w
volatileでどんなコード吐くかみんとハマるよ
javaやC#ならvolatileで充分だろうな。 CとC++のvolatileは別もんだから役に立たん。 詳しくはC++11スレを見てこい。
volatileかmutexかなんてのはこっちでする話だろうに なんであのスレでしつこく長引いてたんだか
C/C++のvolatileはvolatileで目的があって用意されたものだがマルチスレッドと直接関係はない低水準機能で、 使う場合もあれば使わない場合もあると。 volatile std::atomic<T>はJavaのvolatileとほぼ同じ意味だそうだが。
コンパイラによる静的な省略や並び替えは抑制できるけど CPUが実行時に行う最適化には関与しないから無意味
はあ?
>>750 atomic_int a = 0, b = 0;
//thread1
a.store_release(1);
int v = a.load_acquire();
int x = b.load_acquire();
//thread2
b.store_release(1);
int w = b.load_acquire();
int y = a.load_acquire();
のときでも x == 0 && y == 0 はありうる?
意味不明なこと言ってるのがわかってないの?
>>764 //thread1
int v = a.load_acquire();
int x = b.load_acquire();
a.store_release(1);
//thread2
int w = b.load_acquire();
int y = a.load_acquire();
b.store_release(1);
リオーダーされてこうなったら全部0
769 :
768 :2011/10/23(日) 22:24:48.00
>>767 すまん勘違いしてた。同じa同士のloadとstoreはひっくり返るはずが無いと思ったが実際の動作ならそうなりえるよね。
>>760 それvolatile無くてもJavaのvolatileと同じ。
volatile変数としてatomicを使えるようになってるだけで、
特別扱いはない。
>>767 ,769
同じスレッド上でのリオーダーの話と別のスレッドから見たときの順序の話がごちゃ混ぜになってないか?
a.store_release(1);
int v = a.load_acquire();//a.store_releaseとa.load_acquireは同じオブジェクトなのでリオーダーできない。
int x = b.load_acquire();//その結果b.load_acquireも上に移動できない。
しかしながらseq_cstじゃ無いので他のスレッドから見たときの順序が保障されないので x == 0 && y == 0 はありうる
これでいいんじゃね?
そのコードで会話が成立してるところが凄いかも
いまから一生懸命C++11での質問してる人がいるけど、 まともに使えるコンパイラでてんの? メモリバリアとかよくわかんないなら、 今使えるライブラリを動かして勉強した方が早いんとちゃう? 3年後11に本腰入れたって出遅れはしないだろ。
3年後には次の規格が出てるよ
>>738 なみの処理じゃ、IOの影響がでかすぎて、
速度の優劣はIO次第になるな。
例えば、1600個の画像からMD5を採ったとき、
IO状態次第で0.7秒から、1分40秒もの差がでる。
恐らく前者はキャッシュ効果だろう。
スレッドを4本でスレッドプール使って計算したが、
確かに計算は速いものの、結局IOがもたつくとどうしようもなく遅い。
【OS】 WindowsXP SP3 【言語】 c++ 【実行環境】VC++ 2010 + boost 【その他特記する事項】- 以下に示す2パターンの記述で、どっちでもイイヨ…、どちらが良い、どちらもダメで他の方法が良いか、ご指導お願いします。 マルチスレッド処理するクラス(以下、クラスA)をつくっています。 以下のスレッドを生成します。 ・ネットワーク経由でデータを受信する ・受信したデータを内部で加工する ・加工したデータを画面に表示する スレッドを実行する方法について考えています。 { クラスAのインスタンスaを作成 aとスレッド関数名を指定してスレッド生成・開始×3 join } とするか { クラスAのインスタンスを生成して コンストラクタ内でスレッドを生成・開始 }// デストラクタ内でjoin とするか迷っています。 普通は前者のようにする気がします。 後者にすると、一見スレッドが生成されていることに気がつきません。 ですが、クラス・インスタンスの独立性的なもので考えると後者でも良いような気がしました。 が、結局、デストラクタでjoinすることで、 元のスレッドが、a配下のスレッドの終了を待機してしまう、という訳のわからなさがあります。 以上、よろしくお願いします。
どうでもいいよ どっちみちそんな手軽にあちこちで無意識に使うもんじゃないでしょ
デストラクタでJoin失敗したらどうすんの
スレッドがどうとかより機能別に関数を作れ
781 :
777 :2011/10/25(火) 12:55:15.17
レスどうもです。 >どうでもいいよ 作法とかあったらしりたいなぁ、と思いました。(マルチスレッド自体はじめてで。) 今回は簡単なツールなので確かにどうでもいいのですが…。 >Join失敗したらどうすんの 失敗するのですか? 戻り値がvoidだったので気にしてませんでした。 例外が投げられるのかな。調べてみます。
782 :
777 :2011/10/25(火) 13:10:39.43
あれ? 結局デストラクタでJoin失敗した場合と、デストラクタじゃない方でJoin失敗した場合とで、どういう違いが起きるのです? >スレッドがどうとかより機能別に関数を作れ 一つのクラスに押し込めるな、ということでしょうか? 関数は各スレッドで(クラス内で)独立したものを使っていて、 関数間のデータの受け渡しもクラス内のメンバ変数を使っているので、 クラスの使い方的に、理にかなっているかなぁなんて考えたのですが…。
構造体や変数に volatile とつけたときの 本当の意味を知る方法
784 :
777 :2011/10/25(火) 14:47:21.75
レスどうもです。 >構造体や変数に volatile とつけたときの volatileとか初めて知りました。何てこと…。 でも、コンパイルのコード生成的なオプションで、マルチスレッド指定していれば、変な最適化はされなくないですか? >どちらもダメで他の方法が良いか に対するレスですよね? 781か782でしょうか?
>>777 受信スレッドと加工スレッドと表示スレッドに分けるんだろ。
で、スレッド起動したら基本は動きっぱなしだと理解したんだが。
それなら、受信クラスと加工クラスと表示クラスに分けて、
スレッド起動(受信クラス、ネットワーク情報、受信バッファ)
スレッド起動(加工クラス、受信バッファ、表示キュー)
スレッド起動(表示クラス、表示キュー、表示デバイス情報)
こんな感じで起動すればいいんじゃないのかね。
こういう作りにしておけば、例えばメインスレッドで表示をするように変更するのも簡単だ。
TBB使えば
787 :
777 :2011/10/25(火) 17:02:22.59
>受信スレッドと加工スレッドと表示スレッドに分けるんだろ。 >で、スレッド起動したら基本は動きっぱなしだと理解したんだが。 はい。 >こんな感じで起動すればいいんじゃないのかね。 了解です。 変にまとめすぎない方がいい感じなんですね。 「独立して動くスレッド達のだから、メインでは、何もしないのがいいのかなぁとか無駄に凝ってました。 >TBB使えば それは、どのような意図でです? boostとそっくりな気がして、どの様にとりあつかえばヨイのか見当がつかないです。
788 :
777 :2011/10/25(火) 17:13:53.40
detach()というメソッドが何を目的にしているのかいまいち理解できないので教えて欲しいです。
>>785 を利用させてもらうと、boost::threadを使う場合(thread_groupで無い場合)
boost::thread スレッド起動1(受信スレッド関数名、受信クラス、ネットワーク情報、受信バッファ)
boost::thread スレッド起動2(加工スレッド関数名、加工クラス、受信バッファ、表示キュー)
boost::thread スレッド起動3(表示スレッド関数名、表示クラス、表示キュー、表示デバイス情報)
で、スレッドを起動しますが、
「あとは、エラー出ても、例外投げても、私は知らないから勝手にやってね。」という場合は、
スレッド起動1.detach(); スレッド起動2.detach(); スレッド起動3.detach();
と書いてしまっていいんですか?
join()しないと、メモリ的に何かおかしいことになりそうな気がして、ドキュメントを探しているのですが、捗っていないです。
デタッチ自体初めて知った概念なので、理解がすすまないです。
デタッチ:デバッガなどが監視・制御の対象としていた(アタッチしていた)実行中のプログラム(プロセス)を監視下から外すことを「デタッチする」という。
というのは、わかったのですが、自動変数である「スレッド起動x」は、メイン終了で開放されるのではないのですか?
>>788 pthread_detachとCloseHandleをスレッドに対して
実行した場合を調べてみ。
790 :
デフォルトの名無しさん :2011/11/03(木) 18:34:53.11
visual c++ 2010 Express についてくる、 Concurrency::concurrent_queue を使って、 要素にstringを含んだ構造体(そういえばstringだけって試してないな)を取り扱うと、 デストラクタで開放するときに、アクセス違反が起きるんですけどどうすればいいですか? という質問をしたいのですけど、Visual C++を教えるスレッドへ行ったほうがいいです? とりあえず、英語圏で同じ問題を出している人をみつけたんですけど、みたいな状態で、アロケータ?なんだそりゃ?な状態なのです。とりあえず英語読んできます。 ageて申し訳ない。
791 :
790 :2011/11/03(木) 18:39:17.13
申し訳ないです。 よく考えたら、Concurrency::concurrent_queueとマルチスレッドって関係浅いですね。 他で訊きなおします。 失礼しました。
792 :
デフォルトの名無しさん :2011/11/03(木) 20:00:51.82
そういえばppl.hのメモリリークのバグっていつの間にかなおってたな
p://ideone.com/CZz2M Concurrency::parallel_forを使っているかたはいらっしゃらないでしょうか。 画像処理のシミュレータをVC2008Expで書いていて CreateThreadによる手書きマルチスレッドからOpenMPと移行し 速度的に変わっていないことを確認したのですが VC2010Expに移行し、OpenMPの導入方法がわからなかったので parallel_forに書き換えてみた所、異常に遅いのです。 プロジェクトの設定は、2008はリリースデフォルト+OpenMPサポート 2010はリリースデフォルトです。 何か設定を間違っているのかと思うのですが、どなたかわかりませんか? 【OS】XP sp3 32bit 【言語】VC++ 2008/2010 Express 【実行環境】 Core 2 Extreme X9650 3.45Ghzくらい
プログラミング初心者で課題が出たんですけど… 教えて頂けるとありがたいですm(__)m ・九九の表をVisual Basicで完成させる ・1から100までの整数の和を求める お願いします
マルチスレッドで九九表を作るという課題かもしれない
処理そのもののコストよりもスレッド作るコストの方がでがいわw
>>797 つまり、よりコストを下げるためにFiberを実装する宿題と言うことか。
教官が採点不能すぐるwww
SSE使おうぜ
SSEを使ったからといって、マルチスレッドとはいえないがな。
数値計算ならSSEとマルチスレッドを両方使うのが常識だな
ならGPGPUで
SSE+マルチスレッドなら九九ならず9999999×9999999くらいの表を作るべきだな
約100T個
GPGPUってマルチスレッドなのか? 一応処理単位をスレッドと呼ぶけどそれじゃSSEもマルチスレッドになるような 数値計算だとデータ並列が基本だから数値計算プログラムを書く人から見たら いわゆるマルチスレッドと大して違わないんだろうが
GPGPUもSSEも「並列化プログラミング」だよね ただそれらはスレッド無しでも使える技術だから、このスレでは微妙かも 以前は並列処理スレがあったけど、そちらはdat落ちした
SSEはSIMDだろ、んでGPGPUとスレッドはMIMD。 SSEとGPGPUは機能としては勿論、分類としても全然違うと思うぞ。
GPGPUで重要な性質はSIMDだろ いかにSIMDを生かせるかで性能が決まって、アルゴリズムもそれが前提になる
GPGPUの各クラスタというか構成単位について見ると 同時に異なる命令を実行していることがあり得るので Single Instructionではない フリンの分類に当てはめるならMIMD しかし、もっと狭めたSPMDっていう表現のほうが適切じゃないの
複数の別々の画像に対して同じ処理を並列に独立に実行したら タスク並列かデータ並列かどっちになるの?
どっちも使ってるで良いだろ
GPUは投機実行するか、単に並列実行するかで方向性がかなり変わるよね。 もっとも、GPGPUとしては投機実行の方が需要が多いだろうけど。 投機実行となると実行してる命令はクラスタ毎に異なるから やっぱMIMDとしての使用がメインという事でないか。
GPGPUは「ゆかいな牧場」のメロディーで発音したくなる。
大人になってから改めて歌詞を見ると下ネタにしか見えないな
818 :
デフォルトの名無しさん :2011/11/22(火) 19:52:25.40
シングルスレッ〜ドでコード おまえ書いてたころ〜
人というのは知っている言葉を敏感に聞きとれるようになっている
すなわち、それは
>>817 がエロくなっただけのこと
かゆいな牧場
atomic_store、stomic_load関数って自分で実装しなくてはならない羽目になったらどうするんですか WindowsAPIを探してみたんですがよくわかりません Interlockedシリーズを応用するんでしょうか?
メモリ競合は、あるスレッドがあるアドレス位置に書き込みを行っている最中に、 別のスレッドがそのアドレス位置に書き込み、もしくは読み込みを行うことで、 そのアドレス位置に中途半端にデータが書き込まれた状態で別のデータが書き込まれる、 あるいは読み込まれることによって起こる、という認識で正しいでしょうか? その場合、それはビット単位で起こるのでしょうか? たとえば以下のように、ある変数に2スレッドで書き込み、1スレッド読み込む場合、 変数の値が 0x00, 0xff 以外の値になることはあるでしょうか? もし変数のサイズがもっと大きければどうでしょう? // thread0 var = 0x00; // thread1 var = 0xff; // thread2 if( var ) ; // ...
>>822 環境次第。その対象アドレスにあるのが普通のメモリなら、ビット単位と言う事は無いのでその2値以外になることはおそらくない。
>>822 どのサイズが問題なく読み書きできるかは環境(CPUやVM等)しだい
(intはOKだがdoubleはだめといった感じ)
>>822 32ビットx86なら4バイトアライメントされたアドレスの4バイトをmovでアトミックに書き込める、
これが8バイトだとmov2回になるので(もっと違う値なら)2値のどちらでもない状態が存在する、とかいうのはある
でも付いて行けなくなるから考えないほうがいいぞ
>>823-825 ありがとうございます。
とりあえず、メモリを読み書きする電気的な信号などがバッティングして
データが飛んだりハードが壊れたりということはないんですね。
メモリ競合程度でハード自体が壊れるなら欠陥品と言わざるを得ない
>>826 その環境が組み込みでメモリマップドI/Oの先にいい加減な回路が繋がっていたりしたら、壊れるかも知れんが。
尤も、そんな回路ならマルチスレッドに関係なく壊しそうだけど。
そんなハードウェア上で何も組める気がしないぜ
831 :
デフォルトの名無しさん :2012/01/15(日) 18:00:02.48
物理ディスクとのI/Oコストってデカイじゃん もしかしたらアーカイブのままメモリに読み込んで、 メモリ中でアーカイブ展開しながら処理した方が 早いんじゃないかとも思うんだが、 検証しやすいサンプルとか無い? 高速展開と、部分抽出が出来れば効果が現れやすいと思う。
>>831 20年くらい前に、そういうコンセプトのフリーウェアがあったっけな。
とりあえず試してみたら良いだろ。
圧縮率を20%と仮定するなら、100KBのreadにかかる時間と、
80KBのreadにかかる時間差を計測する。
後はオンメモリに置いといて、その時間差ないに解凍できるかだ。
ちなみにディスクの待ち時間の大部分はヘッドのシーク。
データサイズが多少小さくなったところで、得られる時間は少ない。
データが連続している場合、20KB減ったところで1msも短くならないぞ。
何だ無駄か。読み込みスレッドで随時解凍しながら取り込めば、 ワーカーの処理待ちを減らせるかと思ったのに。
いや、IO自体のオーバーヘッドは今でもバカにならない。 ネットワーク上のファイルIOもレイテンシがでかい。 いまどき数百MBからGBオーバーのファイルも少なくないんだから、本気でバッファを大きくとるか、コンカレントに処理して欲しい。 アーカイバをいくつか使い比べると何割というレベルの速度差がある。 速い奴はちゃんとそういう所にも気を配ってる。
そういえば昔、NetWareというサーバOSがあったな クライアントのローカルHDDをアクセスするよりも LANでつながったNetWareサーバ上のファイルをアクセスする方が高速だった 古きよき時代
JavaのFutureとpthread_joinとの違いが、 スレッドプール使えるかどうかぐらいしか解からん。 アレは、pthread_joinとスレッドプール以外じゃ何が違うの? (オブジェクトと例外返すのは置いといて)
いやFutureは結果返すためのものだからそれ置いといたらダメだろ
pthread_joinも結果は返せるからね。 pthread_joinを軽くラップするだけで、 例外を返すのもオブジェクトを返すのも簡単にできちゃう。 結果を返す事だけに注目すると差異としてはあまりに小さいと思うけど。
>>831 読みきってから処理するのではなく
読みながら処理する
840 :
デフォルトの名無しさん :2012/01/16(月) 13:00:46.78
無圧縮データでディスクIOが、どれくらい コスト掛かるのか調べてみた。 調べ方は2つスレッドを走らせ、 片方はひたすらカウント、 もう片方はファイル読み込みしながら、 読み込んだバイト数分だけカウント。 どちらもカウント変数をクリティカルセクションで囲んだ。 CPUは2コア。 この条件で実行するとファイル読み込み してるほうが1/8程度遅かった 遅い遅い言うけどそうでも無いのな。
キャッシュ読んでるだけじゃないのそれ
まぁ、NTFSの圧縮ファイルシステム使って早くなるなら、 みんな圧縮してるよね。
それは一旦全部解答してから読み込むからでしょ
2chのログは圧縮フォルダに入れた方が圧倒的に速い
パソコン側のHDDキャッシュがお馬鹿ってことじゃあ
ディスク絡みのスレッドの話だけど、HDDのランダムアクセスの遅さに驚愕した。 任意のスレッド数(プール使用)で、複数同時にファイルを読み込み、 MD5ハッシュを取り出してファイル比較するツールを作った。 んで、1ファイル1MB未満のファイル群と、1ファイル40MBを超える ファイル群に対して実行してみた。4コア環境で実行したら 1MB未満だと3スレッドが最速。40MB以上だと1スレッドが最速ってな結果になった。 40MB以上で、1スレッドだとディスクアクセスが100MB/sを超える。 40MB以上で、4スレッドだとディスクアクセスは30MB/s未満まで低下した。 みんなは、この辺どう回避してんの?
>>848 非同期IOとか、メモリマップドファイルとか。
複数スレッドから同時アクセスなんかしたら、ディスクシークが増えて、
帰って遅くなるのは当たり前。
>>848 NCQにまかせて神に祈る
ってのは冗談で
1. 読む順番が決まっているならデータをデフラグでその順番に並べておく
2. その順番に読めるように1スレッドで読みに行く
>>849 理屈じゃ分かっちゃいたんだけどねぇ。まさかここまで遅いとは・・・。
>>850 並列化は諦めるしかないのかねぇ。
ファイルを読むスレッド(1つだけ)とMD5の計算他をするスレッドを分けるとか? CPU時間がどっちかに偏ってたらだめかもしれませんが。
853 :
852 :2012/02/22(水) 00:34:57.35
って850さんが既に言ってますね。ファイルを読むスレッド1+それ以外の計算をするスレッド複数。 そしてディスクアクセスの時間>>計算の時間なら、ディスクが物理的に1つしかない以上は並列化は無理かと。
>>852 それが微妙なんだよね。
MD5の計算って一般的に順序依存があるから、
1つ前に計算した計算結果が無いと、
次の計算が始められないんだよ。
そんなんもんで、ファイル別なら順序依存が無いから
とりあえず、1スレッド1ファイル処理にしてたんだけど。
実は、ディスクアクセスというよりMD5の
順序依存が一番足引っ張ってんのかもね。
あと、MD5の計算時間だけど読み込みの10倍遅いよ。
>>854 〜かもね、とかの妄想に付き合うのは疲れるから、調べてから書けよ
>>855 調べるつってもなぁ。発想の問題じゃない?
これ以上調べられることあるかい?
頼むから喧嘩はやめてくれよな
> 順序依存が一番足引っ張ってんのかもね。 を明らかにすればいいじゃない
>あと、MD5の計算時間だけど読み込みの10倍遅いよ。 あれ?それならいけるんじゃない? 仮に11コアのCPUがあったとして、 1コア目→ディスクから10個のファイルを読み出してメモリに吐く 2〜11コア目→1コア1ファイル分担当で計算 って形で10コアまでスケールするはずだと思うんだけど。コアはスレッドと読み替えてもok。
>>859 ロード時間L, MD5計算時間Mとすると(L=10M)
馬鹿正直にやったら10(L+M) = 110M
お前のやり方だと10L+M = 101M
どこがスケールしてるんだ?
ついでに2スレッドでも101Mは出ると思う
>>860 ごめんどっちが遅いのか勘違いした
吊ってくるわ
>>854 計算が10倍遅いなら、シングルリーダスレッドでも十分にペイする。
ただ、机上で計算すればあんたの実測値なら3並列と4並列に分かれ目がある。
ファイル一件の読み込みを1、比較するってことなんでサイズは全ファイル
ほぼそろってるとして、4対象の場合のそれぞれの最長パスは
1リーダ+4計算スレッド: 4+10 = 14
全部で1スレッド: 1*4+10*4 = 44
4(リーダ+計算)スレッド:1*(100/30)+10 = 13.33 (100MB/sが4スレで30MB/sになったから)
まあ実測すると他のプロセスとかとの兼ね合いでまた変わるだろうけど、
多分安定度で言えばシングルリーダスレッド+N計算スレッドじゃないかなあ。
OSのページキャッシュに乗っている事が期待できる状況ならまた別だけど。
>>858 ディスクアクセスの改善が無理ならMD5の
順序依存を直すしか無いと言えるんだけど。
もう本当に打つ手がないか意見が聞けないとなんとも。
>>859 確かにね。最終的にはそれが一番効率がいいのかなとも
思うんだけど、ただその方法は計算するファイルは1ファイルまるごと
読み込まないといけないんだよね。
そこがちょっともっといい方法が無いかと引っかかるよ。
864 :
859 :2012/02/22(水) 01:45:16.15
861が俺のレスみたいに見えるので一応自己弁護しておこうw ロード時間L, MD5計算時間Mとすると10L=M シングルスレッド→10(L+M)=110L 11コアによるマルチスレッド→10L+M=10.1L とほぼ11倍の性能ということで理屈上スケールはするはずだ、と。もう寝るおやすみ〜
866 :
860 :2012/02/22(水) 01:47:47.73
867 :
859 :2012/02/22(水) 01:49:07.58
俺のアホー マルチスレッドは10L+M=20Lだ。効率は50%弱か。今度こそおやすみー
868 :
862 :2012/02/22(水) 02:01:42.37
見直すといろいろあれだったので気にしないでw
thread一つ、非同期読込と計算を交互に行う。
読み込み時間がクリティカルなんだから 読み込みスレッドが他の作業をしたらダメなんじゃないの?
HDD一個に複数からアクセスすれば、パフォーマンス低下するのが当然じゃあ
SSDなら実測値が結構改善するんかね 大して普及してないから宛にならんけど
スレッド制御に頭使いすぎてI/Oウエイトによる遅延完全に無視してない?
いやだから。 SSDがとんだけ普及してるか、は実測値に影響する項なのか?ってことだろ
普及してるかどうかは実測値には影響しないよ。 SSD上での実測値改善が見られるとありがたいけど、 世の中SSD搭載してないPCも多いから、 SSDだけで速くなるプログラムはよくないよねって話しだし。
そっちかよ 自分とこの環境で動かすんじゃないのか
自作のハッシュ計算ツールだけど、MD5計算速度はキャッシュに乗ってる状態だと 3GHz弱のCore2Duo程度のCPUでも300MB/sは超えてるぞ。 計算のが十倍遅いってどういうことだ? HDDなんて速くても100MB/s題だと思うが…
スレッド構成を書いてもらわないとなんとも言えないなぁ 単にシングルスレッドなら100MB/s超えるしね
>>879 読み込み時間を差し引いた計算時間はどれぐらいだったの?
>>879 300MB/sってのは、MD5の関数なりクラスなりが1秒間に
計算できた情報量という理解であってる?
読み込みと計算は別スレッドで同時にやってるから正確には分からんな。 まあいろいろ状況によって時間が変わるけど、計算だけなら最速時で400MB/sくらいだった希ガス。 ああもちろん、読み込みやってもキャッシュに乗ってたら最速だとほぼ同じくらいまで行くよ。
純粋な計算速度が負けるってのは構成が gcc+linux+Phenom X4 1.8Ghz だからなのかねぇ
885 :
デフォルトの名無しさん :2012/02/25(土) 14:26:44.01
ちょっとスレッドとは違うかもしれないんだけど メッセージキューを設計しています シグナルハンドラからキューに積みたいんですが どうしても排他制御ができません うまい方法はありますでしょうか
886 :
885 :2012/02/25(土) 14:28:07.28
自己解決しました
C# の.NET4.0なんですけど List<Double> hoge は適当な値が入っているとして Parallel.For(0,hoge.Count,(val)=> { hoge[val] = 0.0; }); とした場合、常にhogeの中身が全て0.0になりますか? この処理はLockしなくても大丈夫のような気がするんですが少し心配です。
MSの今のList<T>の実装では問題ないはずだけど保証されているわけではない でもそれデリゲート呼び出しのコストがかさむから普通にループ回したほうが速いだろ 並列でやるんなら、4コアなら領域を4分割して中でループ回したほうがいい
つまり、
>>887 を
Parallel.Invoke(()=>
{
for(int i = 0;hoge.Count/4;i++)
{
hoge[i] = 0.0;
}
},
()=>
{
for(int i = hoge.Count/4;(hoge.Count/4)*2;i++)
{
hoge[i] = 0.0;
}
} ・・・(以下略)
とした方が良いということですか?
訂正 読み取りだけならスレッドセーフだと書いてあるな
いくつかstatic変数があって、それぞれに書き込み続ける スレッドを作ったのですが、コンテキストスイッチが発生 しまくってます(2000〜3000/秒) int a, b, c; DWORD __stdcall A(void*){ a = ... } DWORD __stdcall B(void*){ b = ... } DWORD __stdcall C(void*){ c = ... } それぞれのスレッドを単独で実行させた場合は、それほど スイッチしないので、キャッシュ競合が原因なんでしょうか。 それぞれの変数が同じキャッシュラインに乗らないようにするには どうすれば良いですか? それともキャッシュは関係ないですか? VC10です。
なんでキャッシュでコンテキストスイッチが起こるのよ…
>>891 コンテキストスイッチは関係ない。
>それぞれの変数が同じキャッシュラインに乗らないようにするには
キャッシュは8〜32バイトぐらいの単位で管理しているから、
適当に無駄なメモリを確保して、それぞれのメモリアドレスが
隣接しないようにすればよい。
>それぞれのスレッドを単独で実行させた場合 はああ?
メモリバリアの間違い?
なんでメモリバリアが出てくんだよ
コンテキストスイッチみたいなのはCPUを占有すると起こるものなの 無限ループしてパソコンがハングしたらどうするつもりなんだろうね
1スレッドで実行→コンテキストスイッチが起こらない 3スレッドで実行→コンテキストスイッチが起こりまくる これのどこが悪いのか俺にはわからないのだがとりあえずCPUはいくつある?
>>898 cpuは4コアです。
>>897 各ループにSleepは挟んでます。
>>893 無駄なメモリを置いて、キャッシュ対策しようと思います。
また、コンテキストスイッチ数が多いのは、別の原因を探してみます。
Sleep入れたらそりゃぁ、コンテキストスイッチもするだろうよ。
コンテキストスイッチさせるのがSleepの目的のひとつだもんよ。
902 :
デフォルトの名無しさん :2012/03/01(木) 16:16:45.26
static変数に書き込み続けるスレッドとか Sleep挟んでますとか キャッシュ競合を避けるとか 何 考 え て る の よ ?
マルチプロセスほど枯れきっちゃいない技術だから、ということでしょうがあんめぇ
スレッドとかどう捉えてるんだろうね?
>Sleep 噴いたわw
Windowsなんて常時、100スレッド以上動いてるのに。
4CPU環境、速い順に キャッシュラインを別にした3thread キャッシュラインが同じっぽい3thread threadを作らずに1thread
>>907 >キャッシュラインが同じっぽい3thread
>threadを作らずに1thread
このふたつどっちが早いかは環境やプログラムによるだろ。
後者の方が早くなる事もあるよ。
環境と粒度に依存。
メインプロセスと同じ物理コア内のHyperThreading論理コアで実行されている サブプロセスが、メインプロセスの動作を邪魔しないようにするためのAPI関数は ありませんか? 例えば、SetProcessAffinityMaskを同じ値にした2つのプロセスは SetPriorityClassでサブの優先度を下げれば、メインプロセスが 動いているときはサブプロセスはほとんど動作しなくなります。 しかし、SetProcessAffinityMaskを、メインプロセスで1、サブプロセスで2に した場合、サブプロセスの優先度が低いにもかかわらず、メインプロセスと CPUリソースを均等に割り振っているようです。 これを防ぐための、SetProcessPriorityに変わるようなAPI関数はありませんか?
911 :
910 :2012/03/26(月) 16:18:58.25
superπを2つのフォルダにコピーして1つをメイン、もう1つをサブとする。 メインのPriorityClassをNORMAL、AffinityMaskを1に固定。 サブのPriorityClassとAffinityMaskを変化させたときの、2つのsuperπの 838万桁計算時間を比較。 記号 P サブのPriorityClass, A: サブのAffinityMask: メインの時間/サブの時間 A P NORMAL, A 1: 5:19/5:22 B P BELOW, A 1: 2:57/5:38 C P NORMAL, A 2: 3:31/3:30 D P BELOW, A 2: 3:30/3:30 E P NORMAL, A 4: 2:53/2:47 F P BELOW, A 4: 2:52/2:47 Dのパターンでのタイムを見ると、サブの優先度がメインより低いにもかかわらず Cのパターンと同じになっています。 この状況でメインのタイムはFと同等で、サブのタイムはBよりは短くなるような、 SetPriorityClassのような関数はありませんか?
そんなaffinity maskを設定するのが悪い
下手の考え休むに似たり。
914 :
910 :2012/03/26(月) 16:56:47.14
AffinityMaskを設定したのは、確実に再現させるためです。 実際には設定しなくても、多くのプロセスが動いている場合に 優先度の高いプロセスが、優先度の低いプロセスに阻害される 可能性を排除したいのです。
そんなπとかどーでもいいもん計算せずに実用的なもんつくれよ。 πなんて20桁でもあれば地球の外周を計算できるぞ。
>>910 >メインプロセスの動作を邪魔しないようにするためのAPI関数はありませんか?
OSは何?
>Dのパターンでのタイムを見ると、サブの優先度がメインより低いにもかかわらず
>Cのパターンと同じになっています。
もしかしてWindows?
Windowsにはプライオリティブーストなど、CPU占有率の高いプロセスのプライ
オリティを強制的に下げる機能や、アクティブウィンドウを持つプロセスの
プライオリティを強制的に上げる機能があるから、設定した通りのプライオリティ
で動作している事は保証されないよ?
917 :
910 :2012/03/27(火) 09:12:32.64
>そんなπとか superπを作っているのではなく、優先度の制御ソフトを作ろうとしています。 具体的には動画エンコードしながらゲームしているのですが、 core 2のときはエンコーダのプロセス優先度をIDLEかBELOW_NORMALにしておけば ゲームのフレームレートが落ちることはなかったのですが、 core i7にしたら落ちるようになってしまったのです。
918 :
910 :2012/03/27(火) 09:28:22.17
>OSは何? Windows全般ですが、7固有のAPIでもかまいません。 PriorityBoostで優先度が動的に上下するのは知っています。 BのパターンのメインプロセスはE/Fに比べて 若干時間が長くなっており、これがPriorityBoostなどによる 効果だと思いますが、これくらいは問題としていません。
>>917 動画エンコードプロセスに対して、Battle Encoder Shirase みたいな制御をするとか?
>優先度の高いプロセスが、優先度の低いプロセスに阻害される
HTに係るCPUの内部状態を、そのCPU上で動いているプロセスから、
ソフト的に制御する方法なんて無いよ。
ICEでも使って外部からコントロールするなら兎も角。
・・・っていうか、そのアプローチは不可能に近いって何となくわからない?
>Cのパターンと同じになっています。
ソフト(OS)から見たら、HTなんて関係ないし、二つのCPUは等価なのだから、
ソフトにスケジューリングを任せてたら、
二つのスレッドの実行時間がほぼ同じになるのは当然。
>>917 >core i7にしたら落ちるようになってしまったのです。
それホントにCPU依存の話か?
Core2とi7はソケット形状が違うので、CPU以外にも色々と構成が違うはずだが。
VIAとかの互換CPUならともかく、インテル純正CPUでその手の話って聞かないからさ。
もしかしてCore i7のCPU内蔵GPUを殺すと意図したとおりに動いたりとかしないか?
だとしたらGPUとCPUでメモリバス食いあってるか、GPUのハードウェアエンコーダが
有効になってて、GPU食いあってるだけだと思うぞ。
921 :
910 :2012/03/27(火) 10:53:19.74
>919 このソフトを試してみたいと思います。 これでうまくいくようなら、メインプロセスと同じ物理コアの別論理コアで 動くスレッドに対して同じような処理をするプログラムを作ってみようと思います。 >920 ハード的に制御してくれるAPIがないか知りたかったのです。 エンコーダはマルチスレッドですが、GPUは使っていません。 ゲームとエンコーダをE/Fのパターンのように違う物理コアのAffinityMaskにしてしまえば ゲームのフレームレートが落ちないことは確認しました。
>>911 その計算時間どういう操作してどう計ったの?
838万ケタを同時に計算開始しただけ?
論理CPUの割り当てが別なら優先度なんて関係ないに決まってるんだが、意味分かってるか?
ゲームメインを物理コアにだけマスク指定したら問題なさそうな気がするが、それじゃうまくいかないか?
923 :
910 :2012/04/02(月) 12:23:22.30
計算時間はsuperπが計測しています。 同時に計算開始しました。 2つの開始ボタンを押す間の数百ミリ秒は、今回は無視です。 >論理CPUの割り当てが〜 だから、それを優先付けるAPIはないかという質問です。 HyperThreadingを使用するとパフォーマンスが落ちると問題視され Pentium4からずいぶん時間がたったので、そろそろ出ていないかと思いました。 ないので代替案を提示してくださってるのだと思いますが。 >ゲームメインを物理〜 それだと、論理コアが1つ遊んでしまいます。
遊べば他方を圧迫しない、働けば圧迫する HTのために2つあるのは状態に関するレジスタ類だけだもの
自分で設定する気が無いんならOSに任せろ
926 :
915 :2012/04/02(月) 20:57:35.84
既出か。メンゴメンゴ。
>>ゲームメインを物理〜 >それだと、論理コアが1つ遊んでしまいます。 何を言ってるのか分からなくなってきた。 論理コアをあそばせるのがもったいないほどCPUを使い切るマルチスレッド化が出来てるのか? もうちょっと詳しくどういう動作をさせてるのか、どういうスレッド構成になってるのか書いてくれ。 まさかCPUパワーが余ってるのに論理コアが遊んでるのは許せないとかとち狂ったこと言ってないよな、念のために聞くが。
結局のところ
>>924 でどうにもならないんじゃないの?
元の質問に誰も答えないのは、万が一あったりするとアレだからだろうねぇ。 でも、さすがに無いと思うよ、そんなAPIは。 別な方法で妥協するしかないんじゃないかな。
あるか否かは、CPUのニーモニックコードのリストを見ればわかるよ。 そこに命令が用意されていないなら、CPUの内部状態をコントロールしようがない。 非公開命令が用意されている可能性は残るけどな。
結局一緒じゃねーか。 あとそういうニーモニックがあるかどうかじゃ確実には分からんよ。 無いと思うけどね仕組み上から考えても。
そりゃOSレベルじゃ制御してない部分の話だもん。 どころかハードレベルでも制御不能だろってのが優勢。
物理マルチコアにHTなんていらないんじゃないかな
HTをONにすると2000ではひっかかりまくるが、XPではスムーズ。 どうみても対応している。
ただlinuxみたいに同一物理コアの別論理コアに割り当てられたスレッドの優先順位を考慮して タイムスライスの比率を変えるようなことはしてないね。
別コアなのにタイムスライスって、スレッドを一時停止してるっことなんだが、 Linuxではそんなことしてるのか。逆にコスト高くつくんじゃないのか。
941 :
910 :2012/04/04(水) 11:42:02.39
HyperThreadingは空いている演算器を有効に使うためのものなのに メインで使っている演算器も奪ってしまうのはおかしいと考えており 別のOSでは実際にそれを回避するようにもなっているということで とりあえず安心しました。
なんというか・・・ 同時に動かすから、空いてるのを有効に使えるのよ そして同時に動かせば他方を圧迫する 圧迫を回避する=片方を止める=空いてるのを使えてない なのよ
あいつは人の話を聞かないからなあ。 何でも都合よく解釈しやがる。
そんな理論武装で大丈夫か?
pthread_rwlockの使い方をおしえて
2CoreのCPUなら問題ないのに、 HTをONにするとフリーズしたり不安定になるプログラムって何が原因なんだろう?
複数のスレッドを使うプログラムだろうから、スレッド間の同期がいい加減なのだろう。
同時に動くとまずいコードがあるんだろう
2Coreなら大丈夫というのがおかしい。
別におかしくないよ。
いやおかしい。 おかしくないなら、2CoreでOKで、HTだとダメなパターンプリーズ。
ドライバレベルなら昔あったな。 省電力でCPUクロックダウン/休止させる時にHTなので全部止まっちゃいました(テヘっ)ってのが。
試してみて動いた=OKだと思ってるなら根本的に勘違いしてる
>>953 そんなこと考えてる暇あったら、HT時に起こってる問題を正確に掴むべき。
ちょっとしたタイミングの違いで動いたり、動かなかったりなんてのはいくらでもある。
おまえの勘違い半端ねぇ
たまたまの話ならどうでもいい。 頭の悪い突っ込みは必要ないから。
突っ込みはしたものの、 HTだけダメなパターンはなに一つも思いつきませんでした。 ごめんなさい。
お前に思いつくかどうかなんてどうでも良いんだよ。
>ちょっとしたタイミングの違いで動いたり、動かなかったりなんてのはいくらでもある。 この原因は二つ。 ・同期処理をしていない。 ・同期処理が必要な部分を洗い出せていない。 HTがダメで2CoreがOKな理由になってないなぁ。 考える暇がないのか考える頭がないのか。
相談スレで相談したら自分でやれって言う奴を相手にするな。 ただ煽りたいだけの馬鹿なんだから。
現に原因不明の不具合を目の前にして、そんな事考えるだけ無駄だと分からないやつは開発向いてない。
問題の起きるメカニズムを解明するのは興味深いが、 解明したところで自己満足以外に得られるものがないからな 結局きっちり同期するしかないんだし
二つの処理が30ナノ秒以内に終わらないとタイムアウト するウンコな処理があって2CPUだと偶然動いたとか。 KUSOなコードに論理性を求めるほうが時間の無駄。 単にHT環境で再現するという明らかな不具合を直せばよろしい。
Pen4の頃のHTを使っていた時は明らかに普通のデュアルCPUと
タイミングが違ってバグの出方も全然違ったよ
>>965 の言っているように運よく再現できる環境があるなら
そこで治せばいいんじゃない
>>953 1スレッドがループ内でレジスタを使い切るパターンだろ
フリーズまではいかんが、挙動が悪くなる
自分で2CoreではセーフなのにHTをオンにしたら動かない!って言ってるのに、 「そんなパターンは無い!」とか分裂症ですか?って感じ。 そんなパターンがあるからその現象が発生してるのは明らかなのに。 現実逃避もいい加減にしろよ。
スペック厨で、自分の最強ハードに問題が有るって事が気に入らないんだろう 目の前で起きてる問題をどう解決するかが問題なんだがオタクは空気がよめないね
HTをオフにしたら動きました。
>>953 void threadA(){
while(1);
}
void threadB(){
while(1);
}
それのどこがHTがダメなんだ?
>>971 シングルコアならOSがタイムシェアリングして均等に実行してくれる。
マルチコアならOSがそれぞれのコアに割り当てて均等に実行してくれる。
HTだとOSはそれぞれの仮想コアに割り当てて均等に実行しているつもりでも、
片方のスレッドが動いている間、もう片方のスレッドは満足に実行されない。
上のようなBusyLoop場合とくに顕著で、何もしない処理がCPUを占有する事になる。
これを防ぐために何もしないから他の仮想コアに処理を渡してよい事を示す
命令が追加されている。
htでもだいたい均等に割り振られるが。
HT非対応なんだろ
976 :
デフォルトの名無しさん :2012/05/18(金) 21:50:52.80
すいません。教えてください。 signalマスクをかけたスレッドの関数内で、popenをコールしてるんですが、ctrl+Cするとポインタ(NULLでないpopenの戻り値)からのfgetsが成功する時としない時があるんですが留意する事って何かありますか? ちゃんとpthread_joinは出来ているのでマスクには問題無いと思うのですが。 宜しくお願いします。
>>976 どうやってマスクかけたのか、コードをしめせ
>>976 そうだな。エラーコードには留意するんだな。
979 :
デフォルトの名無しさん :2012/06/13(水) 20:18:27.62
並列化できるはずのプログラムをコンパイルして, タスクマネージャーのリソースモニタで見ても, スレッド数が1にしかなりません,どなたか,解決策を教えてください 【OS】 win 7 pro 【言語】 fortran 【実行環境】 インテルR Visual Fortran コンパイラー 11.1 visual studio 2008 【その他特記する事項】 クラーメルの公式で逆行列を求めるプログラムです. 並列化したい部分は以下の通りです. nは行列の行数,aはもともとの行列,bは逆行列の成分です. サブルーチンでは,aの値を読むだけで,変化はさせていないです. その意味でreal*8,valueにしようとしたら,コンパイラに怒られました. プロジェクトのプロパティで, 構成プロパティ-fortran-最適化-並列化onにしています. do i=1,n !-全行に対して do j=1,n !-全列に対して call sho_det(n,i,j,a,b(i,j)) enddo enddo
>並列化できるはず 並列実行できるようなプログラム書かないと
>>980 少なくとも,i,jはいかなる順番で計算しても問題ないという意味では,並列実行できるのではないかと考えましたが,
サブルーチン化しては並列実行できないのでしょうか?
sho_det に並列実行してくれるしかけがあるの?
983 :
デフォルトの名無しさん :2012/06/13(水) 21:13:24.59
じゃあ、自力でできるようにするしか 並列処理したから早くなるというもんでもないだろうに 並列処理できるようにする方が難易度高
>>979 sho_detの中身をくわしく。
特にbへの代入
なぁなぁ、くらーめるの公式ってことは内部で余因子展開やってるよね? 余因子展開は並列和を行うため、一つの行列式は一個のスレッドで固まってないとだめ(もしくはプリフィクススキャン)なので call sho_det(n,i,j,a,b(i,j))がどうやら行列の個々の要素ごとに演算を行なっているように見えるので このループ全体が並列化の対象でない限りはcall sho_det(n,i,j,a,b(i,j))だけがマルチスッドレでもだめなんじゃないの? みたいなことを素人が書いてみましたがどうですか?^^
サブルーチン呼び出しは副作用を仮定して並列化不可能とみなす。 最適化を実行速度以上、かつプロシージャ間の最適化有効なら コンパイラーの気分がいい時にはやるときもある。 とりあえず診断に自動パラレライザーのレポートがあるならそれを付けろ。
988 :
デフォルトの名無しさん :2012/06/14(木) 12:17:59.33
ソースを示した方が早くてわかりやすいと思うので,アップします.
http://www5.puny.jp/uploader/info/upload_id/1669260777 pass:giko
>>987 レポートはこれで合ってますでしょうか?
プロジェクト '20120528_fast_pararell_subroutine'、構成 'Release|x64' の中間ファイルと出力ファイルを削除しています。
コンパイルしています インテル(R) Visual Fortran 11.1.067 [インテル(R) 64]...
ifort /nologo /Qparallel /module:"x64\Release\\" /object:"x64\Release\\"
/libs:static /threads /c /Qvc9 /Qlocation,link,"c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\bin\amd64"
"C:\Users\my_note\Desktop\fortran\20120528_fast_pararell_subroutine\20120528_fast_pararell_subroutine\20120528_fast_pararell_subroutine.f90"
リンクしています...
Link /OUT:"x64\Release\20120528_fast_pararell_subroutine.exe" /INCREMENTAL:NO /NOLOGO /MANIFEST
/MANIFESTFILE:"C:\Users\my_note\Desktop\fortran\20120528_fast_pararell_subroutine\20120528_fast_pararell_subroutine\x64\Release\20120528_fast_pararell_subroutine.exe.intermediate.manifest"
/SUBSYSTEM:CONSOLE /IMPLIB:"C:\Users\my_note\Desktop\fortran\20120528_fast_pararell_subroutine\20120528_fast_pararell_subroutine\x64\Release\20120528_fast_pararell_subroutine.lib" "x64\Release\20120528_fast_pararell_subroutine.obj"
Link: executing 'link'
マニフェストを埋め込んでいます...
mt.exe /nologo /outputresource:"C:\Users\my_note\Desktop\fortran\20120528_fast_pararell_subroutine\20120528_fast_pararell_subroutine\x64\Release\20120528_fast_pararell_subroutine.exe;#1"
/manifest "C:\Users\my_note\Desktop\fortran\20120528_fast_pararell_subroutine\20120528_fast_pararell_subroutine\x64\Release\20120528_fast_pararell_subroutine.exe.intermediate.manifest"
20120528_fast_pararell_subroutine - エラー 0、警告 0
989 :
988 :2012/06/14(木) 12:22:04.79
ちなみに,サブルーチンに入れる前でも,マルチスレッド化はされませんでした. i,jのdo内で,コールしている部分にそのままサブルーチンの中身を書いていました. その際,shoi(),shoj(),k,min_more,sekiなど, ローカルな変数はすべて配列化して,引数に(i,j)をとり, コンパイラにはdoの順序が任意であるように伝わるようにしたのですが, それでもだめでした.
クラーメルの公式って並列処理できるものなの? から考えませう
>>987 (´・∀・`)ヘー単にライブラリ追加するだけのオプションじゃないのか
オプション /Qpar-report3を付けてコンパイルするんだ。 並列化阻害要因が表示されるはず。
/Qpar_report3だったかも。
>>994 omp parallel
って、そういう使い方するもんじゃないような、よーしらんけど
上の続き 単純な2重ループだけだと、スレッド化してくれん ループが二組以上でデータ等の依存関係がない場合にそれぞれのループをスレッド化してくれる って、バカなりに解釈したけど
とりあえずサブルーチン化により並列実行でマズそうな点は解消されてるっぽいが
まぁコンパイラーの /Qparallel じゃ分からないくらいには複雑と思われる。
>>979 > VALUE属性はスカラ仮引数にのみ指定可能です。
ttp://www.nag-j.co.jp/fortran/fortran2003/Fortran2003_8_18.html そういう意味を明示するなら引数授受特性を書いて
PURE 手続きにしてやると上手くいくかもしれない?
ttp://www.xlsoft.com/jp/products/intel/cvf/docs/vf-html/az/az09_39.htm pure subroutine sho_det(n,i,j,a,b)
implicit none
integer, intent(in) :: n,i,j
real*8, intent(in) :: a(n,n)
real*8, intent(inout) :: b
略)
!!-----------小行列用に,i,jを飛ばした自然数の並びを作成 の部分は最適化できそうだけど、自力で...
1001 :
1001 :
Over 1000 Thread このスレッドは1000を超えました。 もう書けないので、新しいスレッドを立ててくださいです。。。