2チャンネルもマルチスレッドですね!
5 :
デフォルトの名無しさん :2007/08/14(火) 18:31:20
Symbianケータイで初めて、同期/非同期ってのやったけど、 わけわからんかったなぁ・・・
マルチスレッドアプリの設計パターンを学ぶのに良い本orサイトありませんか できれば対象言語はC++/Posixでおねがいします
設計を学ぶのに言語なんか関係ないと思うが。 それとも実装を学びたいの?
>>6 Java言語で学ぶデザインパターン入門 マルチスレッド編
結城 浩 (著)
Java並行処理プログラミング ―その「基盤」と「最新API」を究める
Brain Goetz (著), Joshua Bloch (著), Doug Lea (著)
どちらもJavaだけど、現時点でマルチスレッドを学ぶのに
一番適した環境はJavaだと思うので、この辺がオススメ。
C++で使いたいならC++の水準に落とすだけなので損はない。
後者は必ずしも必要ではない情報だと思うけど、
Javaではpthreadより低水準も高水準もカバーできる環境で、
その詳細な内容まで触れられているので参考になると思う。
>>7 いや他の言語知らないのでサンプルソースとかが読めないと辛いかなと
>>8 レスありがとう。やっぱりJavaになってしまうのか
本屋で手にとって確認してみます
下のやつは、かなりおすすめ。
つかさ、やっぱ推薦図書テンプレ化した方がいいんでね?
>>6 プログラムデザインのためのパターン言語
ソフトバンク刊
ねぇねぇ メモリブロックとCASの順序ってどうすればいいの? mb() CAS() mb() って感じでいいの? あと、マルチスレッドでアルゴリズムが正しいか検証する場合って みんなどうしてる?長い時間動かして動いてるor正しそうだからオケって 感じ?それともなんかtool使ってるの?
競合がおこりそうな状況を作ってぶん回すのはやる それ以上はどうだろう・・・
CASやるときはメモリバリア要らないと思う でもまぁ環境分からないし、プロセッサのマニュアルを確認してくれとしか 検証はどうするんだろうねぇ・・・
>>13 CASの対象にメモリバリアが必要だったら意味がないと思う。
事前の読み込み前に同期させたいなら話は別だが。
mutexのロック回数とか計測したいときってみんなどうしてるの? 目視w?
なんらかの監視機構を利用する。
いまどきのJVMでの競合のないロックって、 CAS2回程度だったりするってどっかで聞いたけど。 ぶっちゃけ下手なことするくらいならロックのがましじゃね?
>>19 競合の可能性が高くなければlock freeにするメリットは低い。
ほとんどの場合はロックの方が検証の意味で安全、確実。
いまどきのJVMがどのような実装になってるもんなのか知らないけど、 たとえば.NETだと、標準のlockはCASとスピンウェイトでそれでも競合したときだけ スレッドの切り替えが起こるような実装になってると読んだ。 で競合がない場合はlock取得と開放でCAS2回だと。 これだとlock内での操作が非常に少ない場合、ほとんどlockでいい気がする。
ああ、要は、下手にlockフリーにしようとしてCAS操作を何回もやってしまうような実装だと、 何も考えずにlockしたほうがましってことね。
吉野家コピペと一緒。 両刃の剣。素人(ry STMが一般的になれば話は変わってくるんだろうね。
___ / \ クスクスッ /ノ \ u. \ !? / (●) (●) \ | (__人__) u. | \ u.` ⌒´ / ____ / \!?? / u ノ \ クスクスッ / u (●) \ | (__人__)| \ u .` ⌒/ ____ / \ /\ キリッ . / (ー) (ー)\ / ⌒(__人__)⌒ \ | |r┬-| | \ `ー'´ /
using System; using System.Threading; public class CyclicBuffer<T> where T : class { private static readonly bool s_multiProcsessors = Environment.ProcessorCount > 1; private volatile int m_head; private int m_reserve; private int m_tail; private readonly T[] m_buffer; CyclicBuffer(int capacity) { m_buffer = new T[capacity + 1]; } public bool Enqueue(T value) { int current; int next; do { Thread.MemoryBarrier(); current = m_reserve; next = NextIndex(current); if (next == m_tail) return false; } while (Interlocked.CompareExchange(ref m_reserve, next, current) != current); while (m_head != current || m_buffer[next] != null) Wait(); m_buffer[next] = value; m_head = next; return true; }
続き public T Dequeue() { int current; int next; do { Thread.MemoryBarrier(); current = m_tail; if (current == m_reserve) return null; next = NextIndex(current); } while (Interlocked.CompareExchange(ref m_tail, next, current) != current); while (m_head < current) Wait(); T value = m_buffer[current]; m_buffer[current] = null; Thread.MemoryBarrier(); return value; } private int NextIndex(int current) { return ++current == m_buffer.Length ? 0 : current; } private static void Wait() { if (s_multiProcsessors) Thread.SpinWait(400); else Thread.Sleep(0); } }
ああそうそう、超未検証なのであしからず。 ついでに.NETだが。
バグだらけだったよママン Enqueueは下の間違いわはは たぶんまだバグだらけだなこれは public bool Enqueue(T value) { int current; int next; do { Thread.MemoryBarrier(); current = m_reserve; next = NextIndex(current); if (next == m_tail) return false; } while (Interlocked.CompareExchange(ref m_reserve, next, current) != current); while (m_head != current || m_buffer[current] != null) Wait(); m_buffer[current] = value; m_head = next; return true; }
ちょっとおおぼけかましてたので再度 using System; using System.Threading; public class CyclicBuffer<T> where T : class { private static readonly bool s_multiProcsessors = Environment.ProcessorCount > 1; private int m_head; private int m_tail; private readonly T[] m_buffer; public CyclicBuffer(int capacity) { m_buffer = new T[capacity + 1]; } public bool Enqueue(T value) { int current; int next; do { Thread.MemoryBarrier(); current = m_head; next = NextIndex(current); if (next == m_tail) return false; } while (Interlocked.CompareExchange(ref m_head, next, current) != current); while (m_buffer[current] != null) Wait(); m_buffer[current] = value; return true; }
続き public T Dequeue() { int current; int next; do { Thread.MemoryBarrier(); current = m_tail; if (current == m_head) return null; next = NextIndex(current); } while (Interlocked.CompareExchange(ref m_tail, next, current) != current); T value; while ((value = m_buffer[current]) == null) Wait(); m_buffer[current] = null; Thread.MemoryBarrier(); return value; } private int NextIndex(int current) { return ++current == m_buffer.Length ? 0 : current; } private static void Wait() { if (s_multiProcsessors) Thread.SpinWait(400); else Thread.Sleep(0); Thread.MemoryBarrier(); } } もうだめかもorz
そしてlockと比べて30%かせいぜい40%程度しか変わらんかったw まあシングルコア、シングルプロセッサの環境だからそもそもまともに試せんがw
メモリバリアやめて変数自体volatileにしたら lockと比べて3〜4倍速くなったバロス。
つまらないからどうでもいいんだが 性能比べるなら最低4CPUで 4から128スレッドまで生成してテストしてくれないかな?
そんなマシンねーんだよ誰かくれ暮れ。 まあそれを言うなら前すれのjavaのを見てみたいがな。 VMのバージョン依存が大きそうだが 新しい環境ならたぶんsynchronizedのが早いんじゃね?
CAS利用したアルゴリズム扱ってる洋書しらん? 和書クソいらん。
和書→(excite)→
using System; using System.Threading; public class CyclicBuffer<T> where T : class { private volatile int m_head; private volatile int m_tail; private volatile T[] m_buffer; public CyclicBuffer(int capacity) { m_buffer = new T[capacity + 1]; } public bool Enqueue(T value) { if (value == null) throw new ArgumentNullException("value"); int current; int next; do { current = m_head; next = current + 1 == m_buffer.Length ? 0 : current + 1; if (next == m_tail || m_buffer[current] != null) return false; } while (Interlocked.CompareExchange(ref m_head, next, current) != current); m_buffer[current] = value; return true; }
public T Dequeue() { int current; int next; do { current = m_tail; if (current == m_head || m_buffer[current] == null) return null; next = current + 1 == m_buffer.Length ? 0 : current + 1; } while (Interlocked.CompareExchange(ref m_tail, next, current) != current); T value = m_buffer[current]; m_buffer[current] = null; return value; } }
今度こそ最後、汎用化バージョン(structでもOK) using System; using System.Threading; public class CyclicBuffer<T> { private volatile int m_head; private volatile int m_tail; private readonly Entry[] m_buffer; public CyclicBuffer(int capacity) { m_buffer = new Entry[capacity + 1]; } public bool Enqueue(T value) { if (value == null) throw new ArgumentNullException("value"); int current; int next; do { current = m_head; next = current + 1 == m_buffer.Length ? 0 : current + 1; if (next == m_tail || m_buffer[current].Stored) return false; } while (Interlocked.CompareExchange(ref m_head, next, current) != current); m_buffer[current].Value = value; m_buffer[current].Stored = true; return true; }
public bool Dequeue(out T value) { int current; int next; do { current = m_tail; if (current == m_head || !m_buffer[current].Stored) { value = default(T); return false; } next = current + 1 == m_buffer.Length ? 0 : current + 1; } while (Interlocked.CompareExchange(ref m_tail, next, current) != current); value = m_buffer[current].Value; m_buffer[current].Value = default(T); m_buffer[current].Stored = false; return true; } private struct Entry { public T Value; public volatile bool Stored; } } しつこくてすまんのう
C#には詳しくないのであれだが, >public bool Dequeue(out T value) なんとなく使いにくそう (´・ω・`)
うん、使いにくい。 でもintとかの値型が対象のときはこうなってないと対応できないんだよね。 まあ、デフォルト値をパラメータで指定するとかって方法もあるにはあるが。
これでCAS操作一回ずつと後はvolatileアクセスだけなので マルチプロセッサ環境でもうまくスケールするかな… シングルの環境では、lockよりも4〜5倍程度速い感じ。
ネタにマジレスするのはどうかと思うが これ整合性とれてねーじゃんw 不完全だろw
整合性ってなあに…?(´・ω・`)
不完全ってなあに…?(´・ω・`)
マジネタにネタレスしたんだろ
こういうの微妙に不思議なんだけど、 シングルプロセッサ環境でも複数スレッドの方が速くなるのな。 なんでだろ?.NET環境特有の現象? 1スレッドと10スレッドでトータルの実行時間は3倍くらいにしかならない。 100スレッドだとせいぜい20倍くらい、つまり5倍くらいスループットが上がる。
それどんなプログラム?
上のやつとか。 CPU(とメモリ)依存処理ばかりなのになんでだろう。
ソースアップしてくれんとわからんね。起動やJITにかかってる時間も含んでる?
計測は、できるだけ実際の実行部分だけになるように 一応注意してやってはいるんだけどねぇ。 今外なのでソースは出せんが、ゲートとカウントダウンラッチ使って 間の時間を計測してる。計測精度は問題ないものを使ってる。StopWatchね。 ラッチは自作だけど、100万回ループの最初と最後だから 実装がいまいちでもまあそれほど大きな影響はないはず。 スレッドが多いほど処理スレッドに割り当てられるCPU時間が ある程度は増えるかも知れないが、5倍てのはそういう問題の範囲じゃないと思うんだよね。
>>39-40 物凄くレアなケースだが、いわゆるABA問題にハマる可能性があるよね。
キューが空のときに、Enqueue()の
> if (next == m_tail || m_buffer[current].Stored) return false;
の行の実行が終わった直後にコンテキストスイッチが入るなどして、次の
> } while (Interlocked.CompareExchange(ref m_head, next, current) != current);
が実行されるまでの間に別スレッドがcapacity + 1回のEnqueue()と1回のDequeue()を行ったとすると、
キューが満杯なのにCompareExchangeが成功してしまう。
同じことはDequeue()側でも起こりうるね。(キューが満杯のとき、Dequeue()内のif文と
CompareExchangeの間で別スレッドがcapacity + 1回のDequeue()と1回のEnqueue()を行った場合とか)
こういう問題への対策法としては、capacityを十分大きくしておくくらいしか
思いつかないけど……
windowsアプリでやってるので、後でコンソールでも試してみよう。 あとは、スレッド1このときにメインスレッドで直接実行してどうなるか、かな。
>>53 なるほど、ちゃんと考えてないけど確かになりそうだ。
やっぱ更新バージョンが必要になるのかなぁ…
いや、更新バージョンじゃだめだな。 インデックスの扱いを工夫、かな。
つーかみんな論文とか読んで先人はどう工夫した かぐらい考えてからソースコードかけよなぁ
>>53 変数は配列長の整数倍でできるだけ長い周期でループするようにして、
インデックス使用時に配列長で剰余をとるようにしたら、結構遅くなったw
インデックスで必要なビット長を求めて、残りの上位ビットを
サイクル数のカウンタとして使用するようにしたらだいぶ速くなった。
前のよりは1割程度遅くなったが、ここらでいっぱいいっぱいかな。
>>59 そんな申し訳ないことして実際どれぐらい役に立つのw
オナニーバイナリ生成ぐらいがいいとこだよね?
日本語でOK お前さんは役に立たないことは一切やらないのかね?
まあいろんなものを実装する練習になるから まったく役に立たないわけでもないんだけどな。
>>62 中途半端にかじった奴が糞コード晒すのとどうか思うのだが?
使えるならまだしも危険すぎだろwこんな糞コードしかかけないんだから
止めろよ。ゆとり夏房は本当に困る
どしたん?
>>63 「これこれの理由で危険だから使わないように」とでもコメントすれば済むことではないかと。
糞なとこを指摘してやれば役にも立つのに。 >使えるならまだしも危険すぎだろw いや誰も実際に使おうなんてやつはいないだろw
>>66 こういうものは指摘しても理解できないだろ?
俺はこんなコード書くやつがまともな姿をした
人間だとはとても思えないんだよ。
>>59 ていうか配列長を2の冪乗に切り上げておけば、
ビットマスクとのAND演算だけで済むでしょ。
それは思ったが、無駄が多かったのと、キャパとの兼ね合いで 空もしくは一杯の判定が微妙にややこしくなりそうなのでやめた。 でも確かにサイクルカウントを上位ビットに持つよりはずっと単純だったかも試練。
70 :
68 :2007/08/19(日) 00:10:34
>>69 いや、capacityも配列長に合わせて切り上げちゃっていいんじゃない?
どうせパフォーマンス重視なんだから、capacityなんて厳密に扱う必要はないと思うが。
うーん、容量固定のキューだったからね、今回はこれは変えたらだめかなって勝手に。 まあ、実際にこんなものを作ることがあったらそうすると思う。
>>67 >こういうものは指摘しても理解できないだろ?
ここは相談室なんだから、相談相手になる気がないなら他へどうぞ
>>58 マルチスレッドに限らず、Windowsプログラミング全般においてその本は
とても有用なので、買って損はないよ。
ただし、各種オブジェクト単体での深い説明が中心で、スレッドの作法だとか
そんな話は皆無で、マルチスレッドの入門書として期待しているなら
やめた方がいい。
例えば、クリティカルセクションが他の同期オブジェクトよりも軽いという点について、
OS内部でどう実装されているのかという話が書いてある。
マルチスレッドの話が読みたいなら「Win32マルチスレッドプログラミング」の方が
いいと思う。(俺は見たことないが)
でどの辺が糞コードでどの辺が中途半端にかじったぽいのか早く教えて
この絡み方厨房の典型だなw
そうやってすぐ厨房扱いする奴も大して変わらん
厨房に厨房が返してるだけだろ
mutexが永田ロックかけてるのか まだロックかけないで痛めつけてるのか 計測するほうほうないですか? pthreadでお願いします。
C言語歴15年とかいう人が ローカルにコピーすれば以下のような コードがOKだと主張するのですが本当なのw? struct data{ int len; char buf[128]; } struct data[6]; int index; これをグローバルで定義しておいて void *thread_1(void *arg){ data[index]; //データ書き込み処理 index++; } void *thread_2(void *arg){ int l_index = index; //データ読み込み処理 } 絶対 indexをローカル変数に代入して 順番考慮してないから2回処理しそうな 気がするんだけどさー なんかこんな人のプログラム見るのやだ 逃げたいタスケテ
HPの鯖でpthread使って書いてますけど ファイバってことはありえないですよねw? まじ釣りとかじゃなくて本気でこんなコード生成 するんですよ。困ってる
>>80 オマエの日本語やコードの貼り方も相当なもんだ。困ってる
ごめん許してくれ
マ板向けの話題かな
これって絶対ネタだよな 馬鹿でも考えりゃ排他必要な事解かると
満を持してvolatileの登場だな
>>80 悪いがそのコードの意味がわからなくてなんとも胃炎。
>>89 文脈から想像して、
int l_index = index;
このようにindexをローカル変数にコピーしてから、そのコピーを使って
配列参照すればロックとかいらない、とC言語歴15年さんが主張している。
と読んだ。
ただ、コードは明らかに抜粋なので、状況によってはOKなのかも知れない可能性はある。
thread_1がデータの更新処理で、thread_2は現在の最新データを取得するだけ、
配列は十分に大きく、データの空チェックは別にあるとか。
あるいは、thread_1とthread_2でキューを実現しようとしているなら問題だけど、その場合も
コードが断片すぎるので、前後の記述によっては問題ないかもしれず。
それを含めて
>>80 が明らかな問題であることを認識した上で書き込んでいるなら、
最初からマ板に行くべきかと。
>>90 SMPなんかでCPU入れ替わったら
問題おきないかなぁ?
>>90 キューなどの順序性保証が必要なものだとあきからにやばいけど、
掲示板などに書き込まれたデータの最新の1レコードを定期的に
表示更新っていうパターン(厳密な意味での最新版にはこだわらないもの)
なら、volatileのレベルで妥協できる場合もあるんじゃないかって
思ったんだけど。
thread_2の例が現状のindexをいじらずに現時点のindexのレコード参照
しているだけみたいだから。
絶対2回読む可能性捨てきれないし こんな実装商用レベルでしないよなぁ きっとどっかの研究室だろうなぁ。 教授が書いたコードだから絶対だみたいな感じなんだろうなぁ
それならまさに発見的手法だな
【OS】 WinXP SP2 【言語】 VC8 【実行環境】 2000以降、可能であれば9x以降 【その他突起する事項】 C++ソースコード上での解決が望ましい TerminateThreadだと、終了させたいスレッドのハンドルがあればスレッドを終わらせる事ができますが、 これは基本的に最終手段としてスレッドを終わらせる為の物で、初期のスタック割り当てを解除する機会がなかったり、色々問題があるようです。 なので、スレッド外部からExitThreadの様にスレッドを終わらせるにはどうすればいいんでしょうか。 対象のスレッド内で、終了される"かもしれない"タイミングは把握可能です。
終了フラグを用意して、スレッドが終わって欲しくなったらフラグを立てる。 対象スレッド内で、今だったら別に終了してやってもいいというタイミングで、フラグをチェックして自主的に終了する。 フラグの読み書きは、ちゃんとクリティカルセクションやミューテックスで囲むか、インターロック関数を使うか、メモリバリアを張ること。
・終われフラグなりイベントなりを用意 ・要所要所でフラグ/イベントをチェックしてオレオレ例外をthrow ・スレッドの開始点でtry〜catch でとりあえずできる 他のやり方でも結局こうなると思う コールスタックにC関数が挟まるとダメな場合もあるので注意
98 :
.95 :2007/08/28(火) 23:18:11
Sleepしてる間に終わらせるフラグが立つので、待ち時間が長いです...
>>95 メッセージなり何なりを対象スレッドに投げて、対象スレッドに自ら涅槃の道に旅立ってもらう。
>>98 Sleepを細かく分ければいい。
for (int i=0; i < 10; ++i) {
Sleep(100);
check_exit_flag();
}
こういうポーリングがいやならEventつかって待機関数で待つとか
【OS】 Xp sp2 【言語】 VBA 【実行環境】 Q6600 VBAってマルチスレッドできないともできるとも明記されていないんです。 質問なんですが、VBAにかかわらずマルチスレッド化によって、『比較的発生しやすい障害』というのは何でしょうか? C等ならPUSH、POP等のメモリ操作がいちばん気をつかいそうなところですよね。 VBAでは、適所に Do Eventを2つ入れること(実験により1つではエラー起きやすい)、変数のグローバル宣言にきをつけること(2つのスレッドで同じ変数を呼ばない)ことくらいですかね。プロシージャーは同時に使っても今のところ問題ありません。 どうぞよろしくお願いします。
>【言語】 VBA >VBAにかかわらず どっちだよ
>マルチスレッド化によって、『比較的発生しやすい障害』 >101のような香具師が手を出してプロジェクトを台無しにする可能性が高まること。
日本語でおk
> VBAってマルチスレッドできないともできるとも明記されていないんです。 M$に問い合わせろよ
煽る人ばっかりで、本日はまともな人いないんですねー。>< 失礼しました!
>C等ならPUSH、POP等のメモリ操作がいちばん気をつかいそうなところですよね。 お前はいったい何を言っている?
Cカップの子を触るのにおもいっきり触るのか それともソフトタッチでいくのかこれは結構気を使うって ことなんだな
PUSH,POPは気を使わない。それぞれ単純に排他制御するだけだ。 気を使うのは、例えば何かの目的のために一つの処理の中で pop,pushを続けて行おうとたらその間に別スレッドが実行されて 意図せず状態が変わってしまうようなことが発生すること。 排他制御していない箇所はどんなタイミングでどのスレッドが 実行されるかわからないことを肝に銘じておく必要がある。 『実験により1つではエラー起きやすい』 こんなこと言ってるようじゃ駄目だ。なぜ1つでエラーと なったのか論理的に分かるまで追え。まあDoEventを愛用 する奴にはマルチスレッドは剥いていない
VBAってCOMオブジェクト主体じゃないのか マルチスレッドの意味あんのかな
>101 VBA単独でスレッドを起こす手段がないからな。明記する必要もないだろ。 VBAだけじゃMutexとか同期用のオブジェクトをどうやって扱ったらいいものか、 スレッドを起こす手段がないので同期に関する記述もないからなぁ。 それにCOMだし意味がないかもな。
113 :
デフォルトの名無しさん :2007/09/08(土) 01:29:00
適当なスレが判断できないのでここで質問させて下さい。 msvcrt.dllやスタティックなVC6以降のmallocとfreeの動作についてですが、 _beginthreadexで作成した各スレッドで、あるスレッドがmallocしたメモリを 違うスレッドでfreeする事は合法でしょうか? 過去の自分の書いたコードで見つけてしまいました。 なんかやばそうな気はするんですが。
>>113 何を知りたいの?もうちょっと明確に話まとめろよ
このインキン野郎が
>>113 スレッドが異なることは問題ない。
メモリ管理で問題になるのはモジュール(EXEやDLL)が異なる場合。
ただし、この場合でもすべてのモジュールのCランタイムを
動的リンク(msvcrXX.dllを使う)にしておけば、問題は発生しないはず。
116 :
デフォルトの名無しさん :2007/09/08(土) 21:25:21
ありがとうございました。 一応きちんと動いてはいるみたいなので放置します。
マルチスレっ
合法か違法かで言えば合法だろうし、(問題でてないのに)直すってのもアレだけど、 行儀わるいよな。
>>118 アプリ全体のログを採る処理で、printfみたいな書式文字列を
mallocやreallocでメモリに貯めていって、ある程度溜まった段階で
清書してファイルに吐き出して、使った分をfreeしてくという仕組みなんですが、
CriticalSectionの排他で順番だけ決めてるだけで、どのスレッドが
メモリ管理をする、というのを決めてないんです。
まあ、最初と最後の破棄とかはメインスレッドがするんですが。
試しにスレッド間通信したらパフォーマンスが悪かったので
こんな仕様にしたような記憶があります。
どうしたらいいでしょうかね。
きちんと管理できてるんなら問題ないでしょ。 C++ならstd::stringとか使ってくれた方が楽そうだけど
マニアックにboost ropeで
boost? STLportじゃなくて?
XP/2000のスレッドで質問です。 親子関係にあるスレッドで、親をなるべくブロックさせずに、 毎秒数KB程度のデータを子に送信したいと考えています。 (子は1つで、子の応答はいくら遅れてもかまわない) クリティカルセクションでデータの排他をに試したら、 子供の処理が長引くだけ親がブロックされてしまうので、 別の方法を検討しています。 こういった場合、スレッド同士の同期オブジェクトを介さずに データをバッファに溜めておける名前付きパイプが良いかなと 思ったのですが、こういった用途に使えるでしょうか。
パイプの長さは必ず確保するという話ではなかった気がするなあ >クリティカルセクションでデータの排他をに試したら、 >子供の処理が長引くだけ親がブロックされてしまうので 通常、 バッファへの追加 バッファからの取り出し 以外は排他する必要はないと思うんだが、違うのか?
>>123 子スレッドが処理終わるまでロックさせっぱなしにしないで、
さっさと必要なデータをコピーしてクリティカルセクションから抜けたら?
10ヶ月かかるし。
処理が終わるまで待ってたらスレッドの意味が無い。
129 :
デフォルトの名無しさん :2007/09/19(水) 20:55:43
【OS】 Debian Etch Linux kernel 2.6.18 【言語】 C pthread 【実行環境】 GNU gdb 6.4.90-debian gdbでのマルチスレッドのデバッグ中、任意のスレッドでステップ実行をしていると とつぜんカレントスレッドが切り替わり、 ステップ実行していたスレッドの実行位置が失われる現象に遭遇します。 デバッグ対象のプログラムは、動作確認がとれているオープンソースのプログラムです。 原因、回避法等ご存知のかた、ご教示いただけないでしょうか
gccスレにも行っとけ
>>129 250万でサポートしてやるけどどうよ?
250万の内訳を教えてくダサイ
サンドバック料:200万 治療代:50万
>>132 年間保守契約費 200万
登録費 30万
事務手数料 20万
だが?
ずいぶんと安いね
これからはsignalfdだな
ロックしたら負けかな、と思ってる
138 :
デフォルトの名無しさん :2007/09/24(月) 18:56:19
erlangマンセー
malloc(), free()ってスレッドセーフなんですか?
お前が使っているライブラリのマニュアル嫁
>>140 man malloc
ってやってもスレッドセーフに関する記述がないんです...
使っているOSの名前、バージョンを言わないのは初心者気取りか?
対応してる。大丈夫だ。
藻前詐欺にあい易いタイプだろ
ワロタ
昔おれ衝動買いの時によくやった 店員に騙されるパターン 信じてたのに・・・・
148 :
デフォルトの名無しさん :2007/09/30(日) 01:20:45
マルチスレッドでcoutを使うと表示がぐちょぐちょになって醜いです。 どうしたらいいでしょうか?
C++の仕様。 printf使いなさい。
すみませんprintfでも同じです
coutという一つの資源を複数のスレッドで取り合うからそうなる。 排他機構を使ってひとつのスレッドが使っているときに他のスレッドが使うことが無いようにしろ。
出力スレッドでも作って、そいつに全部押しつけろ。
pthreadつかってマルチスレッドのプログラム作ってるんだけど. なぜか特定のタイミングでピタッと動かなくなる(デッドロックというのか?) それ以降プログラムがうんともすんともいわなくなる. デバッグする際にみんなどういうことやってる?gdbは使い物にならないし...ltraceも使えない... やっぱりソースコードを目で追っていってるわけ?
154 :
148 :2007/09/30(日) 10:48:06
>>151-152 そんな事したらめんどくさくないですか?
もうちょっと簡単な方法でお願いします
ソースを追うっていうか、どんなケースが起こりえて、 すべてのケースの組み合わせに対応できているか検証する。 大体は、止まりそうな場所はわかるから、そこを調べて、 次に、ブロックするかもしれない操作を洗い出して調べる。 止まる場所は突き止めたけど、どうして止まってしまうかわからない場合は、 状態をログに出したりするかな。 デッドロックより、最適化とかOoOでの実行順序の入れ替わりとか、 可視性が関わるバグの方が、調べるの大変だと思う。
coutやprintfがMT-safeでも、 出力が崩れるのはどうにもならないと思うので、 出力処理全体を1セットとして、ちゃんと排他しないと駄目だろう。
>>154 マルチスレッドプログラミングが「面倒くさい」ものでないならば
そもそもこんなスレは存在して無いだろうよ。
>>154 ぐちょぐちょにならないっていうことの意味をもっとはっきりしないとだめだね
一番綺麗なのは、スレッドAの表示がすべて終わってからスレッドBの表示をすることだが、それならシングルスレッドにするのが一番簡単
つまりマルチスレッドやめれば解決
>>154 ドトネトのSystem.Consoleクラスならマルチスレッドセーフ。w
>>161 素朴な疑問なんだが、そのマルチスレッドセーフとは出力が混ざらないことまで保障してくれるのかね。
# だとしたら、逆に激しく不便なんだが。
>>158 のは、言われてみれば当たり前なんだが、
簡単だし、間違いないな。
変数/オブジェクトの持ち回りとかが、複雑になってたら、
スレッドローカルな変数を使えばいいし。
メソッド一発分が安全に動くだけだろ。
>>162 Console.WriteLineはアトミックに実行されて出力は混ざらないね。
ReadLineは1つのスレッドが入力実行中は他はブロックされるかな?
混ざらないとどの辺りが激しく不便なのでしょうか?
行単位でも混ざって欲しくなかったら>164では不十分だろ。 行単位で適宜出力して欲しかったら混ざらなかったら不便だろ。
まず、「混ざる」の定義からはじめろ。 バイト単位なのか、 マルチバイト、ワイドキャラクタ等の文字単位なのか、 出力ストリームのメソッド単位なのか、 複数の出力ストリーム書き込みをまとめた、プログラムの中で定めたオレ単位なのか。
初心者なオレのためにライブラリ、クラスのスレッドセーフの 定義を騙ってください。
>>170 メソッド一発分が安全に動くだけ以外のことをされると
マルチスレッドでは激しく使い辛いですな。。
>マルチスレッドでは激しく使い辛いですな。 わかんねー奴に俺が翻訳してやる。 せっかく並列に動くのに余計なロックするなや 別に使い方が面倒になるわけじゃないよ いじょ
173 :
148 :2007/09/30(日) 18:12:10
もういいです。わたしが馬鹿でした もうあきらめます。
なんだ、学習意欲のないやつだな
175 :
148 :2007/09/30(日) 19:21:43
すみませんが、本当にわかる方、回答をお願いします。
残念だったね。
自分でマルチスレッド対応のストリームつくればいいじゃん
178 :
148 :2007/09/30(日) 19:44:05
>>177 そんな事したらめんどくさくないですか?
もうちょっと簡単な方法でお願いします
そもそもプログラミング自体めんどくさくないですか? ありあわせのフリーソフト探してくる方法が簡単だと思います
そもそも生きてるってめんどくさくないですか? 氏ねば簡単ですよ
>>180 どうやったら楽に死ねますか?
簡単そうな方法にはちょっと勇気が必要だし、そうでないのは簡単じゃないし
>>180 旅立ちパックの中に
連単はいってるからつかえ
以上
>181 死ねばすべてが楽になるんだ 楽したいなら、死ぬ努力ぐらいはしてもいいだろ 俺は死にたくないから、努力して生きるよ
>>178 ストリーム出力だけロックすれば済む話だろうが〜
どこが面倒なんじゃ〜?
マルチスレッドプログラミングは初心者には無理だよ 面倒=やり方がよくわからない という事であればこの先できるようになる見込みもなし 厳しいけどこれ現実なのよね
スレッガーさん!
187 :
デフォルトの名無しさん :2007/10/03(水) 20:59:05
スレッドセーフじゃない場合はどうするつもりだったのかと・・・ スレッドセーフだったらどうしたかったのかと・・・ まぁいいや、どうせネタでしょ?
次世代ゲーム機のCPUみたいにレジスタが山ほどあるCPUて コンテキストスイッチのオーバーヘッドも比例して増えてるんかな
一部しか保存しなくてすむようにしてあんじゃね?IA64とかそうだべ。
64bitのレジスタ32本あるのじゃまんぞくしねーのか?
高速なキャッシュがたくさんあれば満足する
IA64とかって確かコンテキストが2500バイトくらいいくんだよなw
おれはレジスタの数よりも、1次キャッシュに乗ってるメモリとの 演算やアクセス速度が、レジスタと同程度であれば良いと思ってる。 結局それが最強でしょ?
命令セットの問題じゃね
だよね。 RISC系の、メモリアクセスは基本的にロード/ストアのみで 演算はレジスタに対してしか出来ない、ってアーキテクチャだと キャッシュの速度だけじゃなく、レジスタの数も欲しいはず。
そんなことできたら苦労は無いわ。 メインメモリにレジスタと同程度でアクセスできれば最強だな。
>>196 補助記憶装置含めて光速の99%で処理できたらおk
発想を逆にするんだ。 レジスタへのアクセスがメインメモリと同程度に遅(ry
じゃあ、みんながのんびりすればよくね?
俺も思う。 CPUだけじゃなくて、日本人がもっとのんびりスベキナンダヨ
1ヶ月くらい休みクレ!
>
>>200 いや、今の状況はさー、
のんびりすべきだ、のんびりしよう、
とか言って急ブレーキ掛けてた頃からは、
実はもうだいぶ経っててさ、逆にのんびりしすぎてるんじゃ?
って密かに周りが焦り始めてるんだけど、
具体的な問題が出てくるまでは、それにあえて気付かない
フリをしていよう、ってところなんだよ。
ほんとうは、そろそろ歩きださないと。いそがないと!
って時なんだよ?
一度怠けると元に戻れなくなるって言うけど、それ以前に
元がどうだったかなんて忘れてるもんだからさ、
フリじゃなくてほんとうに気付いてないのかもしれないね。
日本ヤバイよー。
おれは海外に移住する予定です。
203 :
デフォルトの名無しさん :2007/10/21(日) 20:33:43
SolarisでpthreadでC++です。 C* c; int main() { c = new C; と、mainの先頭で生成したオブジェクトを、N個のスレッド(実際は8個固定)から使っています。 スレッドが順次終了してゆき、最後のN個目が終了した直後、あるいはN-1個目が終了した 後かつN個目が終了する直前にdelete c;をしたいのですが、うまい方法はあるでしょうか。 リファレンスカウントでしょうか。 N個のスレッドすべてをpthread_join()するような、親スレッドはいません。 なお、Cのメンバ関数はすべてスレッドセーフに作られています。 よろしくおねがいします。
>>203 リファレンスカウントで何か不満なの?
boost::shared_ptr ですぐに実装できそうだし。
205 :
203 :2007/10/21(日) 20:41:02
>>204 boostやSTLが使用禁止なので、一から手書きする場合の例をいただけたらと。。
テンプレートは使用可です。
206 :
デフォルトの名無しさん :2007/10/21(日) 20:47:33
>>204 スレッドをまたいでshared_ptrを渡すのって例えばどうやるの?
> boostやSTLが使用禁止なので ぬふぅ
>>203 代入系の演算子をoverrideしまくればそれっぽいの出来るけど、
用途をみてるとそれだけのためにshared_ptrを実装するのはもったいないな。
>>206 スレッドごとに shared_ptr のコピーを持てばいい。
>>210 boostのshared_ptrの参照カウントの上げ下げってスレッドセーフだっけ?
最新のstableでもなにもしてなかったような。
212 :
203 :2007/10/21(日) 23:58:41
みなさまどうも。
>>210 shared_ptr<C> g;
int main() {
g.reset(new C);
// スレッドを8つ生成
cond_wait; // スレッドがgをコピーするのを待つ
g.reset(0);
...
}
void* thr(void* data) {
shared_ptr<C> local = g;
cond_signal;
...
}
とかですか。
チラシの裏で悪いけど、g++のbits/atomicity.hの__exchange_and_add()とか使うと、 libstdc++.soの関数を呼びに行くんだね。おそそー。
>>211 スレッドセーフではないとすると、参照カウントを上げる方は、
>>212 のやりかたでも、一個ずつスレッドを作って、
cond_waitすればいいけど、下げる方は排他制御しないと
駄目って事かな?
単純な実装にするなら、
全スレッドが共用するカウンタを作って、上げ下げすればいいんじゃないのか?
最初と最後だけなら、速さとかは気にせずに、適当な実装でも問題なさそうだし、
atomicな操作ができるなら、それこそカウンタだけ渡せば済むし。
Cがいじれるなら、自分自身でカウントしても良さそうだけど。
どうでもいいけど、
>>212 は、グローバル以外の渡し方はないのか?
>>214 void* data 経由で渡して、スレッド側でstatic_cat<shared_ptr<C*>* >することは可能。
スマートポインタへのポインタを渡すことになって気持ち悪いけど。
どのみちmainは生きてるんだから mainでjoinで待って削除すればいいのでは
>>216 >>203 >N個のスレッドすべてをpthread_join()するような、親スレッドはいません。
クラスCをsingletonにするのは無し?
>>214 そうですね。スマートポインタは使わず、単純なカウンタ+アトミック操作でいこうとおもいます。
>>218 決してdeleteされないsingletonにするのはNGです。threadが全部いなくなったら、deleteしないとまずい
事情があります。
ありがとうございました。
スレッドの調停者が居ない=全てのスレッドが終了時にアプリケーションが終了 なら,singletonでも別にもんだいねーよーな気がする
>>220 スレッドが全部終了した段階では、アプリケーションは終了しません。
また、その段階で~C()をよばないと、いろいろまずいことがあります。
素直にスレッドのマネージャを作れば
224 :
デフォルトの名無しさん :2007/10/22(月) 22:25:30
>>222 メインスレッドaを起点として、ツリー状に生成・所有されています。
a-b-c-N1
-d-N2
e-f-g-N3
-N4
-h-N5-N6
-N7
-N8
みたいなひどい感じです。Nxが、今回興味のあるスレッド群。
何でこんなことになってるのかの経緯は、私にはちょっとわかりません。。。
>>224 こんなはちゃめちゃになるんだったら
マネージャ作れよ
GCとかみたいに自分で管理したくないものは
誰か権限のあるやつだけに委譲しろよ
>>225 managerとは、具体的には何をするものでしょうか?
スレッドのリソースの管理
>>228 アトミックなカウンタ操作があっても実装できない理由って何?
アトミック云々以前にスレッドの管理が出来てないんじゃ意味ないだろ
>>229 複数のCPUが同時にatomic_incを実行すると破綻するから
そんなのはアトミックじゃねぇ
>>231 その atomic_inc はアトミックじゃないのかい?
っSMP
そうでないCPUでは、それはただの x++ とどう違うの?
>>236 横から。わたしもよくわかってないが
1.コンパイラやlibcが提供するatomic_inc/dec関数だけでは、単一CPUでのアトミックな演算しか保証されない
2.適切な命令(バリア)と一緒に使えば、複数のCPUを相手にatomicなinc/decができる (memory visibilityがどーたら)
3.どういうバリアが必要かは場合によって異なるから、コンパイラやlibcが提供するatomic_inc/dec関数にはバリアが入っていないことがある
こんなところじゃない?詳しい人フォローよろ。
238 :
237 :2007/10/22(月) 23:52:39
あー、そういう実装の既存の関数があるのね。 そこまで分かってるなら前後にメモリバリア足せばおしまいじゃね?
240 :
デフォルトの名無しさん :2007/10/23(火) 00:29:35
つーかvolatileで十分w
atomic_inc/readはlinuxのカーネル系の関数のようだね。 pthreadのような高位のAPIを使わない理由はなんだろう? パフォーマンスを気にするようなアプリなのか。
242 :
203 :2007/10/23(火) 00:31:23
>>240 キタ━━━━━━(゚∀゚)━━━━━━ !!!!!
SPARCv9なら、CASがあるよ。
linuxのCでスレッドの排他制御をしたいのですが、 なにぶんPONIX?っていうんですか?での開発は初めてなので ご質問させてください。 pthread_mutex_t mutex; pthread_mutex_init( &mutex, NULL ); pthread_mutex_lock( &mutex ); pthread_mutex_unlock( &mutex ); PONIXではこのようにpthread_mutex_lockを使うようですが この引数pthread_mutex_t*をWin32のCreateThread()のように ある共通の識別子を持っているスレッド同士のみが排他制御を するにはどのようにすればよいのでしょうか? 例えば同じ親から4つ子のスレッドが生まれたとします。 スレッド長男と次男は排他関係 スレッド長女と次女も排他関係 でもスレッド男兄弟とスレッド女姉妹は排他関係ではない という場合です。
必要なだけ mutex を作って、自分で識別子と mutex の対応付けを管理する
自分でご質問とか言うなよ
なぜ?
自分がする質問だから 「あなたのご質問には答えられません」 なら、相手を持ち上げている 「私のご質問に答えてください」 なら、自分を持ち上げている 日本人として変であることに気づくべき
あほか 美化語を知らんのか
おトイレならわかるがご質問はないな。 「ご質問はありますか」は当然あり。
尊敬と謙譲の概念しか無いようだな。
板違い よそでやれ
使い方が間違っているんだよ。 それを気づくことができないのか?
>>254 いやいや、質問する上でのマナーの話だからここで良い
マナーを守れない方がどっか行くべき
>>257 いやいや、ご質問する上でのマナーのお話だからここで良い
おマナーをお守りできない方がどっかへ行くべき
いや、マナーってほどの話ではないとおもう 変な日本語を使ってるけど、意味は理解できるから問題ない てなわけで、おスレち
やっぱ誰でもアクセスできるローレベルな話のほうが伸びるなw
すまんなw おれも、なんか参加しちゃってるよw
しょうがねーな 俺も参加してやろうか
僕もご参加していいですか?
どうぞ、ご参加ください。
265 :
デフォルトの名無しさん :2007/10/23(火) 23:36:57
珍しく盛り上がってると思ったら・・・
>>244 コード例
ひさびさに来ましたよー 相変わらずスレ違いにはレス多いね。
スレッドの呼び出しコストってどうやってはかるの? 組込み用でmutexとかの関数の呼び出しコスト一覧 表作り単位んだけどどうしたらいいん?
>スレッドの呼び出しコスト 具体的にどういう意味と受け取ったらよいのだ?
適当なタイマーで挟んではかr
C++でのマルチスレッドに関する質問です class sample{ private: int i; HANDLE hEvent; public: sample(){ hEvent = CreateEvent(NULL, TRUE, TRUE, L"sample"); } ~sample(){ CloseHandle(hEvent); } void fSetdate(int _i){ WaitForSingleObject(hEvent, INFINITE); ResetEvent(hEvent);//ロック開始 this->i = _i; SetEvent(hEvent);//ロック解除 } int fGetdate(){ WaitForSingleObject(hEvent, INFINITE); ResetEvent(hEvent);//ロック開始 int _i = this->i; SetEvent(hEvent);//ロック解除 return _i; } }
上記のクラスをひとつだけインスタンス化して、 複数のスレッドがそれを呼び出した場合、データの同期化は成立しますか?
何が死体のこれ?
別々のスレッドがfSetdateのResetEventに同時に到達した場合どうすんの?
あべし クラス内部でイベントによってデータの同期をとろうと思ったんですよー。
何でCriticalSection使わんの?
278 :
272 :2007/10/25(木) 10:27:32
イベントを理解しとらんからだろ。 それで同期ってなにが目的なのよ?
正解を書きたいけど、それをコピペして終了されると悲しいので ここは是非MSDNのドキュメントを読むなりして頑張って欲しい。
>>278 イベントとクリティカルセクションがどう違うかなんて、腐るほど説明があるから
いちいち書きたくないが、簡単に言うと
・イベント
遅い
プロセス間の同期に使える
・クリティカルセクション
速い&簡単
スレッド間の同期にしか使えない
あと、その目的でイベントを使うなら自動リセットイベントを使う。
そのコードだと275の懸念していることが、起こるかもしれないという
レベルではなく、確実に起こる。
何をどう同期したいのか分からんから起こっても変わらん気がするw
>>281 初心者に、あまり適当なこと教えるなよ。
それはどちらかというと、MutexとCRITICAL_SECTIONの違いだろ。
EventとCRITICAL_SECTIONの違い、あるいはpthreadにおけるcondとmutexの違いは
同期(実行をコントロールする)か排他(データを保護する)か。
284 :
272 :2007/10/25(木) 18:24:31
みなさんどうもっす。 同期について根本的に勘違いしてました。 データの保護ではCriticalSectionを使うのですね。 でもEnterCriticalSection()が同時に 実行されるということはありませんか?
そんな質問が出るってことは まだCriticalSectionについてググってすらいないようだな…。
>>284 >でもEnterCriticalSection()が同時に
>実行されるということはありませんか?
わらった。
そりゃ同時に実行されるさ。そのためのものだもん。
質問。 今のところはlinuxのpthreadのみを使っていますが、 なるべく一般のスレッドで使えるようにしたいと考えています。 複数のスレッド(X,Y,...)があってそれぞれが独立に動き、 読み込みアクセスrdと書き込みアクセスwrをします。 排他の条件は 1) XのrdとYのrd =>排他しない 2) XのrdとYのwr =>排他する 3) XのwrとYのwr =>排他する 4) XのwrとXのrd => 排他しない(wrの中からrdすることがあるので) となっています。 自力で考えた手法はrwlockを使っています。 4)の条件を満たすためにrでロックする際はtryrdlock()して ・返り値がEDEADLKなら自スレッドがwrlockしているとみなしてロックせずに通す ・それ以外なら他スレッドがwrlockしているとみなして待機する としています。 この手法で移植性は十分でしょうか?
移植性っても、どの程度を考えてるかによるけど、例えば Windows には reader writer lock がそもそもなかったような…
visutaから追加された。
びじゅた?
一般のスレッドって何だよ
なんで4)でrdロックする必要あるの?
ぴゅうた以来 プログラムかいてねーから 鈍ってしまって困った
返答ありがとうございます。
>>288 Windowsのスレッドは触ったことがなく、rwlockがないことを知りませんでした。
>>292 rwlockの状態を知るためにtrylock()しています。
pthreadに現在の状態を問い合わせる関数が見付からなかったのでこのようにしました。
(一般には現在の状態を問い合わせても
次のステップまでその状態が持続するとは限らないことは承知しています)
mutexからrwlockを実装するというのを本で読んだことがあるので
それを参考に実装してみます。
Linuxでpthreadを使用しているのですが valgrindで実行するとfopenとfcloseの箇所で以下のエラーが大量に出ます。 ==25540== Possible data race reading variable at 0x1D52238C ==25540== at 0x674CB5: _IO_un_link_internal (in /lib/tls/libc-2.3.4.so) ==25540== by 0x668A5D: _IO_fclose@@GLIBC_2.1 (in /lib/tls/libc-2.3.4.so) ==25540== Address 0x1D52238C is 52 bytes inside a block of size 352 alloc'd by thread 1 ==25540== at 0x1D4A8090: malloc (vg_replace_malloc.c:131) ==25540== by 0x66935E: __fopen_internal (in /lib/tls/libc-2.3.4.so) ==25540== by 0x66941C: _IO_fopen@@GLIBC_2.1 (in /lib/tls/libc-2.3.4.so) Webで調べるとglibcはすべてスレッドセーフだと書かれているのですが 同期とかしないといけないのでしょうか? 詳しいかた教えてください。
helgrind使ってるって事? あとさ、glibc-2.3.4って偉い古いな。
関数がスレッドセーフであるかと同期が必要かは別問題
>>295 同じdescriptorを同時にopen/closeしにいったらまずいわな。歯痛汁。
299 :
295 :2007/11/15(木) 12:29:07
>>296 CentOS4.5でhelgrind(valgrindは2.2)です。
yumしてみましたがglibcのバージョンは2.3.4が最新でした。
>>297 すみません、語弊がありました。
glibcがスレッドセーフでないならなにか回避策がないと
スレッドでは使用できなくなってしまうので一般的にはどうするのかなと。
>>298 すみません、説明が足りませんでした。
ファイルのオープン、リード、クローズは
すべて同一のスレッド内で行っています。
300 :
295 :2007/11/15(木) 12:30:35
みなさん遅くにありがとうございます。 もう少し調べてみます。
valgrind3.3まで待ったら?
同僚に嫌がらせするだけのために valgrind --tool=erogrindって オプション作って オワタって表示されるようにしたんだけど さっきめっさ怒られたw
303 :
デフォルトの名無しさん :2007/11/17(土) 20:28:57
思いつきだが、最新のvalgrindのsupression fileを使ってhelgrindしてみるのはどうだろうか。
304 :
デフォルトの名無しさん :2007/12/18(火) 09:21:07
Linuxを使った組込機器の開発に、NPTLではなくLinuxThreadsというのを使うことになりました。 これは聞くところによると、あまりOSに頼らずに実装されたスレッドライブラリということですが、 たとえばpthread_mutex_lock関数はどのように実装されているのでしょうか?OSのシステムコール を呼ばない形で実装されているのでしょうか? ソース嫁かもしれませんが、詳しい方いらっしゃいませんか?
アトミックオペレーションができるインストラクションをインラインアセンブラーで記述する事で実現している
しばらくspinしてもロック獲得できなかったらRTシグナル街に入るんだっけ? それはともかく、俺は完全ユーザ空間な1:Nスレッドの実装方法、特にどうスレッドをスケジュールするのかがさっぱりわからない。
green thread
309 :
デフォルトの名無しさん :2007/12/18(火) 21:49:42
310 :
デフォルトの名無しさん :2007/12/19(水) 23:15:10
pthread規格で、 ・端末で^CしたときのSIGINTシグナルは、どのスレッドに届くのか(あるいは全スレッドに届くのか) ・メインスレッドがexit()するとその他のスレッドは終了するのか ・メインでないスレッドがexit()したときはどうか がわかりません。規格上どうなっているか、あるいは最近のLinuxでどうなるか教えていただけないでしょうか? 手元にSolarisしかなくて困ってます。 あ、main関数を実行したスレッドを勝手にメインスレッドと呼びました。
>>310 プロセス宛てのシグナルは、どれか一つのスレッドに届く。どれに届く
かは決められていないので、受け取りたいスレッド以外ではそのシグナ
ルをブロックするようにしておく。
exit()でプロセスが終了する。スレッドは関係ないはず。
スレッドセーフレベルの統一的な呼称ってあります? 引数がスレッドセーフじゃないとか条件付の状態とかあるよね。
シグナル受け専用スレッドって作る?
waitして何かあったらコールバックしてる。
315 :
デフォルトの名無しさん :2007/12/23(日) 19:58:10
pthread_cond_wait()でspurious wakeupが起こるのって具体的にはどういうときでしょうか? どういう順番で、各スレッドの実行や切り替えが起こった場合でしょうか?
.NETのMonitor.Waitでもおこるかどうか知ってる人いませんか?
3000円ちらつかせると 解ってくるかもしれないw
>>315 ,316
マルチスレッドプログラムは基本的に非同期なので、何がおきても対応できるように冗長に作っておいたほうがいいと思う。
>>318 何も言ってないのと同じw
「基本的に」「何がおきても」「冗長に」って.....いかにも何も判ってない奴が使いそうなワードを連発されてもなぁ。
代わりに君が内容の有る事を言ってもいいんだよ
そんなものが書けると思っている段階でダメダメ
322 :
319 :2008/01/02(水) 00:24:53
>>315 >>320 まず、cond_waitしているスレッドがシグナルを受信し、cond_waitがEINTRで戻った場合。
もうひとつ、これをspurious wakeupと呼ぶかは語の定義によるが、cond_wait中のスレッドがwakeさせられた際、
mutexをlockする前に別のスレッドがmutexを先にlockし、条件を偽にした場合。
どちらも、POSIXでは起きてよいことになっているけど、本当に起こり得るかどうかは実装による。
>>316 知らん
323 :
デフォルトの名無しさん :2008/01/02(水) 00:34:36
>>295 去年の12月にhelgrindの新しいの出たらしいよ。
>>295 複数のスレッドからアクセスすれば
"Possible" data race
になるのは当然なような
俺はそういう作り方はしない
>>295 ファイル操作用のスレッドかなにかに
終了通知送って閉じさせろよ
資源の管理はよほどの事情ないかぎり
一括にしろ
いいなわかったか?反論するなら
お前の家にそれは末恐ろしいものを
いくつかぶちまけて逃走するからな?
いいかわかったか?
327 :
デフォルトの名無しさん :2008/01/06(日) 23:38:52
C言語でマルチスレッドに挑戦していまして、 複数の子スレッドを途中停止させ、また再開できるような状態にしたいのですが、 いい方法はありませんか?
>>327 Cでどうやるのか忘れたけど、イベントなりセマフォなりミューテックスなりで待たせるのが
一般的。
329 :
デフォルトの名無しさん :2008/01/06(日) 23:47:25
>>327 pthread_barrier_wait()
とエスパー。
>>327 C言語にスレッドという概念はない。
環境書かないとわかんないよ。
WindowsXPです。
333 :
デフォルトの名無しさん :2008/01/07(月) 11:51:27
レスありがとうございます。 調べましたところ、 WaitForSingleObjectはスレッドがシグナル状態になるまで待ち合わせを行うものだとありましたが、 これをどのように使えばスレッドを途中停止出来るのでしょうか?
>>333 スレッドで考えるんじゃなくて二人以上の作業者による連携プレーを考えろ
で、ひんとはミューテックスオブジェクトかセマフォオブジェクト
スレッドを止めたいって書いてあるのが読めないのか? 答えられないならレスするんじゃねぇよ。
>>335 をつつくとSuspendThread使えとか言い出しそうだな(笑
「いい方法はありません」ってことで。
>WaitForSingleObjectはスレッドがシグナル状態になるまで待ち合わせを行うものだとありましたが、 調べが足りてないね。
Windowsなんて使ってるやつは馬鹿です
「ATOK使うやつは馬鹿」と何かの関係が!?
ここは良心的な釣堀か。入れ食いだな。
なぜ止めたいかを説明してケロ。 他のスレッドを強制的に止めたいのか、何かを待ちたいのか。 スレッドを止める方法はいろいろあるので、目的を説明して。
個人中傷スレだったので・・・
スレッドじゃないけど fork()類って実行間隔って あまりにも短いとダメなのかな?
>>30 msに一度呼ぶと
失敗するような気がするw
そもそもなんでそんなにfork()しなきゃならんのかと。 設計から見直せ。
>>349 fork()する回数は10回なのですが
なるべく速くfork()を10回完了させたいだけですw
OSくらいさらせや
ちなみにSolaris 10 で のことです
errno は?
ダメって何がダメだったのか・・・
356 :
デフォルトの名無しさん :2008/01/12(土) 22:41:41
アセンブリでマルチスレッド これ最速
同期とかも全部asmでやるの?
spin lock
360 :
デフォルトの名無しさん :2008/01/13(日) 20:38:31
fairlock
【OS】Windows Vista Ultimate 【言語】C++ 【実行環境】Visual C++ 2005 Professional, C++ Boost Library 1.34.1 【その他突起する事項】なし bool shouldExit_; istream &is; void handler() { while(!shouldExit_) { string str; is >> str; } } handler関数がthreadのコールバック関数になるのですが この関数を終了させようとしてshouldExit_にtrueを代入しても 入力が内場合、入力演算子を使用しているところでずっと待機してしまいます。 このスレッドを安全に終了させる方法はないでしょうか?
>>362 volatile bool shouldExit_=false;
364 :
306 :2008/01/14(月) 18:08:38
すみません。 漏れていました。 本来のコードには書いてあるのですが、shouldExit_を評価するところまで処理を持って行けません・・・。
>>363 をいをい w
is>>str; でブロックされてるんだからこの場合フラグは関係ないだろ。
とりあえず入力をタイムアウト付きでやるか(C++でどうやるかは知らん)、
可能なら入力ストリームをクローズしてしまえ。
入力を待つけどキャンセルとか強制終了出来るようにしたいんだろ?
367 :
361 :2008/01/14(月) 19:55:45
>>365 istreamの実態はネットワークなので
まさにその方法でうまくいきました。
ありがとうございます。
>>366 もしそれができればそうしたいです。
なるべくstreamに影響を与えたくないです。
368 :
デフォルトの名無しさん :2008/01/14(月) 22:15:59
【OS】 linux fedora 7 【言語】 C 【実行環境】 えー?何て書けばいいのかな? 【その他突起する事項】 特になし 質問ですが、何故pthread_createの第4引数はvoidでキャストするの? argを入れるんだし。たとえば、整数 2を入れる場合も (void *)2 みたいに渡しますよね。 構造体に渡すと言ってもポインタで渡したら良いだけのような.... そのまま入れたらダメな理由は何ですか? 教えてえろい人
なにをやろうとしているかを理解してからやれ、ということ
そういう関数作って そのままいれてみろ
>>368 32bitで済むなら、キャストして無理やり渡したほうが楽ジャン
373 :
デフォルトの名無しさん :2008/01/14(月) 22:35:30
>>369-370 あ、ありがとう。
理解が足りないかもですね。
(int *)でも良いんじゃないですか?って思うんです。
やってみたけど、ダメだよー
なんです。orz
374 :
デフォルトの名無しさん :2008/01/14(月) 22:36:23
あ、64bit環境 gccです
375 :
368 :2008/01/14(月) 22:37:13
373,374も私です。
376 :
デフォルトの名無しさん :2008/01/14(月) 22:39:18
LP64環境か。なら、(void*)2ULLじゃねーの?
377 :
デフォルトの名無しさん :2008/01/14(月) 22:40:18
void* argを数値に戻すときは、int i = (int)(unsigned long long)arg;
378 :
368 :2008/01/14(月) 22:47:29
>376
(void*)2
で動きます。
プリプロセッサがそのように直しているのかも知れません。
>>377 ん?
pthread_create(&th , arg2 , arg3, (void *)2);
みたいに渡しますが
pthread_create(&th , arg2 , arg3, (int *)2);
ではダメな理由は何ですか?
uint64_tって書けよw
380 :
368 :2008/01/14(月) 22:50:20
uint64_tもダメでした キチンとかかず、ごめんなさい
>>380 お前だめだわ
pthread_create()のmanみて
引数の定義どうなってるか調べたか?
そこは何でも受け取れるようにvoid *になってるから
そう渡せやって定義に書いてあるだろボケ
東京湾に沈めるぞドあほ
382 :
368 :2008/01/14(月) 22:57:43
>>381 man見てますよ。
なぜvoidでキャストするの?int*とかでも良いでしょ?ポインタで渡すだけでしょ?
ってことなんです。
383 :
368 :2008/01/14(月) 22:59:01
ポインタで渡す限りintもcharもvoidも関係ないでしょ?って質問です
>>382 なんでint *なの? 汎用ポインタならvoid *が判りやすくていいじゃん。
# それとも、qsort()も使ったことがない人?
C言語の型って何のためにあるかわかる?
関係ないけどC99では整数⇔ポインタ変換する場合はintptr_tを使った方がよくて、 それやらないと最悪strict aliasingの最適化でバグっちゃうケースがあるらしい。
387 :
368 :2008/01/14(月) 23:08:43
>>384 >汎用ポインタならvoid *
大抵、そうですね。
昔、voidに型は無い、という話だったけど、void型という型になっていて浦島
状態です。
>>385 話の流れから、メモリ確保の為。
intのサイズは小さく、他に大きなサイズの時困るって事でしょうけど。
今回は、pthread_create(&th , arg2 , arg3, (int *)2);
のように、サイズが小さくても、不整合は出ないような...
出るのかな?
いや、Cにはvoid型はないけどvoid*型はあるの。
void型はあるよ。 void型へのキャストもできるし。
>>387 サイズ云々はかんけーねーだろ
8byteの汎用アドレス渡すことに
何一々屁理屈こねてるんだアスペル房?
392 :
368 :2008/01/14(月) 23:20:31
>>387 考えがアセンブラだなぁ。
ひょっとして今時オブジェクト指向を理解できてない人?
394 :
368 :2008/01/14(月) 23:22:59
>>393 確かに gcc -Sのコード見たほうがデバッグ早いです。
オブジェクト指向は、時々する程度です
>>392 厳密に型が決まってる言語だから
その場合に曖昧さを表現するには
C言語の場合、簡単な解決方法は
void *で表現すること
理解できないみたいだし四ねw
void hoge(void) { return (void)0; } 規格にも void type とかいう用語は出てくる。
397 :
デフォルトの名無しさん :2008/01/14(月) 23:27:48
>>395 理解しますが
>簡単な解決方法void *で表現
ならば、他に方法は有るのですか?無いのですか?
値は同じでも意味が違うものってあるでしょ。 C言語でいうなら同じ0でも、数学の0と、ポインタのNULLでは意味が違う。 それらを区別するために型という概念がある。 で型があることでコンパイル時に型チェックが可能となって意味の混同が起こってないかを調べられるわけ。
引数に int* ってあるなら、それは32bitの値へのアドレスを渡すということではなくて intの意味を持ったものへのポインタを渡すって理解すべきなの。 だからそこへとある構造体へのポインタを渡すなんてのは設計も使い方も分裂症気味におかしいわけ。
400 :
368 :2008/01/14(月) 23:43:00
>>398 ,399
なるへそ。分かりました。
けど、別の疑問が、**(ポインタのポインタ)で渡したら型の意味もないような
どうでもいいけど、(void *)2はともかく、(int *)2はきもい
*が何個付こうが話は同じ
403 :
368 :2008/01/14(月) 23:59:01
了解。 皆さんありがとうーーーーー。 関数作ってみようか考えていましたが、しなくて良いみたいですね
やけにスレが伸びてるなと思ったらC言語講習会かよ・・・
405 :
デフォルトの名無しさん :2008/01/15(火) 00:34:54
じゃ、pthread_atfork関係でもする?
406 :
デフォルトの名無しさん :2008/01/15(火) 00:37:40
pthread_yield()で頼む。 NPだけど。
なんで?
スレッドで thread1 thread2の2つを走らせている場合 正常狩猟、異常終了両方で2つのthread1 thread2とも同時に終了させて 再度、起動したいのですが、どのようにして終了させたら安全ですか? pthread_cancel(),ptrhread_join,pthread_exit
>>409 そりゃそうだ。
cancel-join
exit-joinが良いのかな?
どうしたら良いかな?
mutexは無しです
thread10個起動して、全部待ちたいときはどうすればいいの?
forでjoin回せば。Win32なら64個までの限定だけどWaitForMultipleObjectsとかあるけど
>>411 pthread_barrier_wait()
あざーす。
すみません スレッドでがんがん動く関数がるけど、この関数は起動字にも動いて処理します。 起動字はスレッド起こしてないんだけどpthread_関係が入っている関数を使っていいの? 具体的にはpthread_atporkです
誤時がおおおいな
あっとぽーくなんてマニアックな関数、何に使うんだか。
deadbeefと関連がありそうだな なさそうでもあるな
>>413 411じゃないけど、pthread_barrier_wait() はlinuxでは無いようです。
どうようの効果を期待できる関数は何ですか?あるいは、その組み合わせは?
教えてちゃんですまそん
>>419 あんたの使ってるディストリビューションが古いだけ。
もっと新しいglibcを積んでるやつを使え。
421 :
デフォルトの名無しさん :2008/01/19(土) 00:46:44
LinuxThreadsの頃からあったと思うんだがな。。。 何使ってんだ??
422 :
デフォルトの名無しさん :2008/01/19(土) 00:48:06
>>419 ほんとにないなら、mutexと条件変数の組み合わせで実現できるけど、結構難しいよ。
NPTLのpthread_barrier_waitの実装を読んで、真似するのが良いと思う。
423 :
419 :2008/01/19(土) 02:35:01
>>420 ,421
cg-linuxていうらしいです。manで無かったんです
かえたらダメだと思います。多分。
kernel=2.4.17?みたいなことします。
pthread.hを見て本当にないか見てみます。
>>422 そんなドキュメントあるんですか、本当になかったら探します。
424 :
デフォルトの名無しさん :2008/01/19(土) 06:58:09
私が小学生の頃、
日本中でノストラダムスの予言が大流行していた。
「1999年の7月に人類は滅亡する!」
という例のお騒がせ終末予言である。
大人になって社会に出て働きだして、
あくせくと忙しく日々を過ごしながら、
1999年は、
ありふれた日常の中であっさりと過ぎていった。
人類は滅ばなかった。
これからここで、
1999年に起こるかもしれなかった人類の壊滅的破局を、
誰にも知られずにこっそりと回避させた人たちがいた...
という設定で、
荒唐無稽なストーリーを描いてみたい。
無論、100%完全なフィクションである。
http://www5.diary.ne.jp/logdisp.cgi?user=532063&log=200705
>>425 くーーー、64bitなんですーーー
探してみますーーーー
こんなサービスもあっ短だメモメモ
bit数関係あんの?
cglinuxってキャリアグレード?
そうだろうね。カーネルバージョン見ると MontaVista っぽい。
だとするなら、サポートしてるかどうかはもんたに聞いた方が良いね。
というか、419が欲しい機能は本当にpthread_barrier_waitで合ってるんだよね?
>>411 を素直に読むと
>>412 で FA だと思うんだが。
(まあ419がちゃんとわかってて聞いてるなら余計なお世話だけど)
matrix * matrixをpthread_createとpthraed_joinだけで、 ぶん回してみたけど(quad core)普通にthread無しで やるほうがはるかに早かった。 pthread_createのコストが高いのかなあ? threadを最初に作っておいてpthraed_cond_wait待っておいてスレッドを使いまわす 方式で再実装してみる。
スレッド数4にしてる?
している/いろいろやってみだ。 4,10,,12,16,32 32だと、たまーにtopでみていると2000%とかになっていた。 それでも、遅い。
×みだ ○みた あと、スレッド数8が抜けていた。
コアが4個なんだからそれより多くしてもほとんどメリットはないだろ
プロセス生成に比べるとマシってだけで、 スレッドの作成(と終了)はそれなりにコスト高いよ。
並列化効率とかアムダールの法則とかでググれ
DualCoreXeon*2で実験した限りでは、core辺り処理量は(殆ど)変わらなかったけどなぁ。 分割の仕方が悪いんで内科医?
>>436 そんなの、スレッド本の第一章に書いてあるだろ。
439 :
デフォルトの名無しさん :2008/01/26(土) 13:54:13
Windowsで 4つのスレッドを開始させ、 一つのスレッドが終了次第、 ほかのスレッドも全て終了させる方法ってありますか?
>>440 すみません。
私の聞き方が曖昧でした。
手段を教えて下さい。
終了すると終了させるは微妙だが大きな違い
>>439 4人の子供のうち、誰か一人でも死んだという通知が来たなら、他の三人に死亡要求を掛ければよろしいかと。
子供が死亡要求を聞き届けてくれない仕様ならば、殺すしかありませんが。
いずれにしても、APIレベルで実装したいならAPIスレ、.Netでやりたいなら.Netスレ、そうでないならVSスレなり
初心者スレなり適当にどうぞ。
WaitForMultipleObjectsで4つのスレッドを待てば、どれか一つのスレッドが 終了したかが判るから、あとは終了イベントたてるなり(スレッドが参照していることが条件だけど)、 TerminateThreadするなり(非推奨)、好きなようにやれば。
マルチスレッド使って、CPU負荷分担みたいなことってできる? 2つのまったく動作が同じスレッド作って、2つのCPUリソースに処理を振り分けるとか?
できるできないで言えば普通できるに決まっとろう。
なにか共通で使うリソースがあって、同時にそれを使えない場合は、 如何に競合を回避するか考えないと、相手のリソース解放を待つのとかで、 同時に動作できる時間が減っちゃう。 CPU1: *-*-* ***--- CPU2: -*-*- とか ---*** こんなのになったら意味無いし。
無駄だけどセマフォしかないわ、全部持つか、一個なら諦めろw
449 :
デフォルトの名無しさん :2008/01/26(土) 21:55:22
Windowsでは、有限バッファ問題(生産者消費者問題)はどう解決するのが良いでしょうか?
http://www.cs.is.noda.tus.ac.jp/~mune/oop/node16.html 生産者も消費者も単一プロセス内のスレッドで、生産者・消費者はそれぞれ複数いるという
状況です。バッファがfullまたはemptyのときは、pushまたはpopの処理がブロックしてかま
いませんが、バッファ長は1や2ではなくもう少し大きくしたいと思っています。
UNIXだと、条件変数かセマフォを使えば簡単に実装できると思いますが、前者はWindowsには
無く、後者は単一プロセス内の同期として用いるのは効率が悪そうです。
Windowsは、VistaではなくXPを使っています。よろしくおねがいします。
450 :
デフォルトの名無しさん :2008/01/26(土) 23:22:41
何でもマルチスレッドにしたがるバカw
>>449 XPには条件変数は無いから。自分で作る。
条件変数って何があれば自作できるんだっけ?
Mutex/CriticalSectionとEventと変数でいいんじゃねーの?
>>453 おそらくその組み合わせでは条件変数もどきは作れないと思うのだが・・。
でも、もし大丈夫だとされている実装とか、MS推奨の実装を知っていたら教えて。
できないと思う理由を書いてくれ。 なんか、条件変数に過大な期待をしてるみたいだから。
broadcast考えなきゃ、Auto Reset Eventを SignalObjectAndWaitで待てば済む話じゃね?
というわけで、producer-consumerのうまいコード例があればお願いします。
投入データの個数をセマフォで管理しとけばいいんじゃないかな データ投入後→セマフォを1上げる データ取り出し前→セマフォを1下げる(データがない=セマフォが0の場合は投入される=1以上になるまでブロック)
>Mutexの開放とEvent待ちをアトミックに行うことができないから。 はいはい。SignalObjectAndWait, SignalObjectAndWait。
>>460 んー、この用途に使えるのか。サンクス。調べてみます。
>>459 最悪それでいこうとおもってます。けど460のでいけるならそれがベター。
というか、Producer-Consumerなら、スレッドプールつかって あとは知らぬの半兵衛を決め込めばいいような気がしてきたぞ。 Producer() { { CriticalSectionLock csl(cs); return if list.full? list.push( somethings ) QueueUserWorkItem( Consumer ); } } Consumer(){ { CriticalSectionLock csl(cs); workitem = pop(); QueueUserWorkItem(Producer); } SomeWork; }
>>462 そういうのもあるんですか。そっちも調べてみます。
ありがと。
464 :
デフォルトの名無しさん :2008/01/27(日) 01:57:33
その場合は、根本から考え直しだよね。 APRみたいに、Manual Rese Eventを待つたびに、待ちスレッド変数をインクリメントして 起こされるとデクリメント。自分が最後に起こされたスレッドかどうかを判断して、 ResetEvent発行するとかさ。
manual resetにするわけか。めんどくさいね。
結論:Windowsはクソ
条件変数を作るとして、それに使うWindowsの同期オブジェクトはどれが軽くてお勧めか?
CriticalSectionにSignalObjectAndWaitできるの?
>>435 thread pool化した。8thread上げといてそれを、
pthread_cond_wait/signal/broadcast
pthreaf_mutex_lock/unlock
で、ぶん回した。
non thread時の倍ほどがのスピードが、漸くでた。
単純にctreate/joinだけだと、メチャメチャコストが高いのですね。
このときは、non thraed時の8倍ほど時間がかかった。
>>468-469 CSが使えないんだとしたらエラく遅くなるよな。
実際のところどうなのか教えてエロい人。
473 :
472 :2008/01/27(日) 18:24:54
VS2005、C++でWin32ウィンドウプログラムを作成しています。 キューの中身が空の間、スレッドを待機させたいのですが、while(que.empty()) { Sleep(0); } とすると、CPUはぶんまわされるわ、スレッド終了フラグも受け取れないわで困っています。 キューにデータが入った瞬間にスレッドが回りはじめ、かつ終了フラグも受け取るためにはどうすればよいのでしょうか? 初歩的な質問ですみませんがよろしくお願いします。
釣り?
いえ、釣りではないのですが… もう少し調べてみます。 それでも分からなければ初心者スレに行きます。 スレ汚し失礼しました
とりあえず、セマフォを使ってみよう。
というか、今までの話題がまさにそのProducer/Consumerパターンについてなわけだが
つうか、セマフォ使えや、カス
メータードセクションだろ普通
484 :
デフォルトの名無しさん :2008/01/28(月) 01:23:40
>>482 へぇ。そんなのあるんだ。プロセス間でも使えて、一定回数はカーネルに落ちないでspin?
全部ホシュするなら、全部ヤッパ明渡せヤゴラ、でOK
?
VMwareでLinux上げてpthread使えば解決
queueに要素があるかは、
>>477 ,
>>481 の通りセマフォでやればいいんじゃない?
増減するリソースを管理するんだからちょうどいいでしょ。
フラグの変更はイベントにでもして一緒に待つか、queueに終了って言うなにかを投げ込めば?
Linux野郎なんでWindowsには全く疎い俺参上! Windowsの独自スレッドだけでpthreadはないの? あと、pthreadとWindowsスレッドを比較した利点・欠点 がまとめてあるHPとないでしょうか?
>>484 スピンで待たせるなら、プロセス内専用だけどWindowにもInitializeCriticalSectionAndSpinCountなんてものもあるよ。
メータードセクションは、Windowsの話だけど・・・
CriticalSectionがspinなのはわかってるよ
どうしてもpthreadがいいなら、pthreads for Win32があるでしょ。 以前mingwでつかってたよ。VCでも使えたはず。
下のようなクラスを作って、Monitorでのロックと比較してみた。
EnterWithContextSwitchで、ロックがほとんどかち合わないで誤差の範囲で軽く、ロックが頻繁な場合だと
明らかに遅くなる。Enterは確実に遅い。
class SpinLock {
volatile int _isEntered;
public void Enter() { while (Interlocked.CompareExchange(ref _isEntered, 1, 0) != 0) { }}
public void EnterWithContextSwitch() {while (Interlocked.CompareExchange(ref _isEntered, 1, 0) != 0) {Thread.Sleep(0);}}
public void Exit() {_isEntered = 0;}
}
//試したのはこんな感じ 各スレッドで
for (int i = 0; i < _loopCount; i++) {
thp.LockDeleg(thp);//ここでLockして
DoWork(_jobTime);//ここで指定時間処理して
thp.UnLockDeleg(thp);//ここでUnlock
}
対象のロックはmontor,SpinLockともども複数生成して、ロックするときにランダムでロック対象を決めるようにした。生成するロック数も多い場合、少ない場合色々試してみた。
環境はXP Sp2 C# .NET2.0 DualCoreのアスロン何たら。
テスト中はCPUを使い切る場合もあれば各CPUが70%ぐらいで推移する場合もあり。どちらのロックでそうなるかは不明。多分SpinLock。
参考URL
http://msdn.microsoft.com/msdnmag/issues/05/10/MemoryModels/ 何か間違ってる?ついでにおまいらのマルチスレッドに関する考え方、使い方を教えてくれ。
教えてエロイ人
何がしたいのこれ?
.netのモニターオブジェクトと自前スピンロックの性能評価?
具体的に何を計りたいのかよくわからん。 ついでについては、ロックがかち合う可能性を下げるように設計する。
499 :
495 :2008/01/29(火) 18:54:29
違う回線よりすいません。 説明不足で申し訳ないです。 言われるとおり、自作スピンロックでどれだけロックが軽くなるかの調査です。 いくつかの記事で、SpinLockでのcpu消費の方が、コンテキスとスイッチより軽いと言っていたので試してみました。 結果が記事と逆になってしまったので自分のコードが何かおかしかったのかと。
スピンロックはマルチプロセッサじゃないと効果無いんじゃないか? スピンしてる間にロックが外れれば、カーネルに落ちなくて済むじゃん
>環境はXP Sp2 C# .NET2.0 DualCoreのアスロン何たら。 って書いてあるから、2つあるんでそ。
あ、ほんとだ。失敬失敬。
単純なサンプルで重い、軽い、と早い、遅いを同列に語っても意味無いかと。 あとSleep(0)の分解能なんてろくに無いんだから いちいちロックされてるたびに呼んでたら無駄に待たされる。 ただ、一般的には、他の誰かが処理してるからCPU時間を明け渡してあげることで いち早くロックを取得できる可能性をあげる意味でSleepを使う Sleep(0)の分解能調べて見て、中のジョブがどれぐらい時間かかってるか 調べて見れば、あなたのいう軽いとか遅いとかがより深く理解できると思う。 Win32だったらCriticalSectionで一発だったんだが .netはLockかInterlockしか無いのかな
public void EnterWithContextSwitch() {while (Interlocked.CompareExchange(ref _isEntered, 1, 0) != 0) {Thread.Sleep(0);}} というか、これ "Sleep(0)" が原因でねーの。他にするタスクがないとき、CPU休まないじゃん。
.NETのロックは元々クリティカルセクションだよ。
単純なスピンロックなんざそもそも間の処理が極めて短時間で 競合なんてまず滅多に起こらん場合にしか向かん。
どうもインタロック操作が極端に軽いと勘違いしてる奴や記事が多いな。 .NETなんて単純にロックでもそう大差はないのに。
ああこれは件のMSDNの記事の事じゃないので念のため。
509 :
495 :2008/01/29(火) 21:59:01
>>21 によれば、.netの機能をそのまま使えば良いんじゃないか?
うんそう。 あえてスピンロックにするのはインタロック操作1回分までも節約したいとき。 2回→1回
512 :
デフォルトの名無しさん :2008/02/03(日) 11:08:05
環境visualstudio2005 vc++ _beginthreadexを使ってメインを合わせて合計3個と100ms毎の割り込みをさせてるんですが、 assert(0)が有効にならない場合があります。マルチスレッドで緊急にプログラムを停止させたい場合は どうすればいいんでしょうか?
ExitProcess
>>512 WaitoForSingleObjectとSetEventを使う。
assert(0)
WaitoSinguruObujecuto と SinguruIvento
SinguruIvento ?
519 :
514 :2008/02/03(日) 21:19:11
ゆるしてっ!!
生成したスレッドから、 ウィンドウハンドルを使用するマクロを使うためにはどうすればいいですかね?
わかりやすい日本語でお願いします。
524 :
デフォルトの名無しさん :2008/02/11(月) 23:34:04
Visual Studio.NET 2003で、Win32API、C++のプログラムをしてるんですが、 複数スレッド同時に、クラスのオブジェクトをnewしまくると、 ・HEAP[aaa.exe]: HEAP: Free Heap block 3c04d0 modified at 3c04e0 after it was freed ・0xC0000005: 場所 0xfeeefeee に書き込み中にアクセス違反が発生しました。 。 ・0xC0000005: 場所 0xfeeefeee を読み込み中にアクセス違反が発生しました。 。 などのエラーがでます。 何か回避方法はないでしょうか? newしてるのは同じクラスのオブジェクトですが、 static変数は持っておらず、グローバル変数も共用してません。 共用のものとしてはstatic関数を持ってますが、使ってはいません。
> 何か回避方法はないでしょうか? バグを直す。
ランタイムがシングルスレッド用になってんじゃね?
527 :
524 :2008/02/12(火) 00:58:26
>>525 シンプルな以下のクラスでテストしてみたんですが、
やっぱり同じエラーが出ます。
class TestClass{
public:
TestClass();
virtual ~TestClass();
};
TestClass::TestClass(){}
TestClass::~TestClass(){}
>>526 ランタイムってなんでしょうか?
VCで設定するものですか?それとも実行する環境に依存するもの?
クラスの定義よりも寧ろ、「newしまくる」方を晒せよ。
529 :
524 :2008/02/12(火) 01:06:18
>>526 ありがとうございます!
VCの設定で、
プロジェクトのプロパティ→C/C++→ランタイムライブラリを、
マルチスレッドデバッグにしたらエラーが出なくなりました。
ヤレヤレ
>>529 シングルスレッド用でコンパイルが通ったてことはCreatThreadを使ってるのかな?_beginthreadExを使ったほうがいいよ。
532 :
524 :2008/02/13(水) 02:11:46
>>531 _beginthreadExは知りませんでした。
調べてみます。ありがとう。
グローバル変数使う標準Cライブラリ(strtokとか)を使う場合、_beginthreadExじゃないとまずいことになる。 そうじゃないならCreateThreadでも特に問題なかったと思う。
>>533 mallocやnewとか、VCランタイムのいろんなものがやばい。
コンパイラベンダでも無い限り、CreateThread使う必要なし。
マルチプロセッサ環境でストアバッファのデータを反映させたい場合 pthreadだとmutex使えばいいんでしょうか?
>>535 同期プリミティブの使用でフラッシュしてくれなかったら、どうにもならない。
537 :
デフォルトの名無しさん :2008/02/14(木) 02:08:24
メモリバリア
539 :
535 :2008/02/14(木) 23:26:30
恥のかきついでに。。。 フラッシュされるということはmutexのアンロック後に 他のスレッドから同期プリミティブを使用せずにメモリを参照しても mutexがアンロックされた時点までの操作は完了してると見なしていい この解釈は合ってるのかな
541 :
535 :2008/02/15(金) 02:19:14
>>539 mutexのアンロックで書き込み側プロセッサのキャッシュがメモリと同期されても、
それだけでは読み込み側プロセッサのキャッシュはメモリと同期されないのでは?
読み込み側にも同期プリミティブ(具体的にはmutexのロック)が必要なはず
543 :
535 :2008/02/16(土) 15:34:51
>>540 の"同時アクセスさえ防いでおけばすべてうまく行く"
というのを信用したんですが・・・どっちが正しい?
キャッシュと同期オブジェクトは別じゃないのか。
同時アクセスを防ぐ=読み側もmutexなりでロックしにいく でも読み込みだけならロックいらないよね。volatile最強!
>>545 一応マジレスしておくと、volatileでは確実に読めることが保証されない。安全を期するならロックした方が楽。
# 理由については割愛。
CPUのマニュアル読むのが一番
>>543 読み込み側もmutexをロックしないと、同時アクセスを防げないじゃないか。
まだ書き込み側がmutexをアンロックする前かもしれないのに。
pthreadの、pthread_join()とsleep()の関係について質問します。 主系スレッドZにて、子スレッドa, b, cをpthread_create()により作成します。子スレッドa, b, cは一定時間経過後に処理を行います。一定時間経過するのを待機する場合、sleep()を使っています。 主系スレッドZでは、子スレッドa, b, cが終了するのを待つために、pthread_join()を使っています。しかし、子スレッドa, b, cがsleep()で待機しているときを、子スレッドが終了した時と勘違いしているようです。 現在では、子スレッドa, b, cが終了する前に、それぞれが主系スレッドZにsignalを送るようにしています。主系スレッドZでは、signalが来るまで待機としています。 最初にやっていた、pthread_join(), sleep()の組合せの方がスマートだと思うのですが、こちらの方法でうまくやるのは無理なのでしょうか?
環境を書き忘れていました。 【OS】debian/etch 【言語】C(pthread/posix) 【実行環境】 glibc2.3.6 gcc4.1.2 kernel 2.6.18-6-486 libpthread NPTL2.3.6
突起フイタ
>主系スレッドZでは、子スレッドa, b, cが終了するのを待つために、 >pthread_join()を使っています。しかし、子スレッドa, b, cがsleep()で待機しているときを、子スレッドが終了した時と勘違いしているようです。 コード晒してみてくれ
553 :
549 :2008/02/17(日) 16:23:25
どうやら勘違いだったようです。 真の原因は、Zでログファイル用に fp_glb=fopen("Z.log","w"); として、fpを持っているのですが、子スレッドが、 fprintf(fp_glb, "log write thread name [a]\n"); として、共通のログファイルに書き込みを行おうすると、死んでいるようでした。子スレッドでは、書き込む前に排他ロックを行っているのですが、主系スレッドでは行っていないことが原因だと思っています。
無茶苦茶だな。
555 :
デフォルトの名無しさん :2008/02/19(火) 09:12:29
VC++にpthreadはないのでしょうか?
自分から終了することもあるし、外部から終了通知を受け取ることもある ようなスレッド関数について質問です。 こういう場合、(スレッド関数はすでに終了してるぞ!)フラグや (外部から終了通知が出されたぞ!)的な何かはいったいどうやって実装していますか? 自分はいつも bool isActive = false; bool IsThreadActive() { lock {return isActive} } void SetThreadActive(bool flag) { lock {isActive = flag; } } void ThreadFunc() { SetThreadActive(true); try { while (IsThreadActive()) { ... いろんな処理 } } catch(...) { SetThreadActive(false); throw; } } 的なやり方でやってしまっているのですが、 これって正しいのでしょうか? また、もしあればもっといい方法を教えていただけると助かります。
558 :
557 :2008/02/20(水) 19:36:19
書き忘れました while (IsThreadActive()) { ... いろんな処理 } の内部から breakで抜けることもあります。 (SetThreadActive(false)も付け足してください)
終了要求フラグとすでに終了してるぞフラグは別にした方がいいんじゃないかな すでに終了してるぞフラグが要るかどうか(何に使うのか)にもよるような
スレッドでいくつかの処理を行いたいのですが、 その処理の内容が 1、実はまったくスレッドが必要にならない場合がある 2、処理の行われる間隔が長いので、 続く処理が無いようならとりあえずスレッドを終了させたい というもので、ある処理のリクエストが入ったとき、 *スレッドが稼動していればそのままリクエストを追加 *稼動していなければ新たにスレッドを起動して処理を開始 *終了要求が入ったらすべてのリクエストを破棄&スレッドを終了 ということがしたいのです。
スレッドを終了する要因がメイン側からの要求だけなら、 スレッドが生きてるかどうかはメイン側が完全に把握してるはずなので、 子スレッド側から「すでに終了してるぞ」フラグを操作する必要はないはず
>>561 スレッドを終了させる要因には、メイン側からの通知もそうですが、
子スレッド内での例外や、自殺も含まれます。
結局、これはフラグで操作するしかないのでしょうか?
というのも、「スレッドをフラグで操るなんて危なすぎ」みたいな話を聞いたことがあるので・・・
それにconditionとか、なんとなくかっちょいい機能を使いたいような気もします
>>561 すいません。分かりにくかったですね。これも追加してください
*リクエストが無ければ、とりあえずスレッドを終了(再びリクエストが来たら再度起動)
例外で死ぬなら、残ったリクエストを誰かが引き継がなきゃいけないような・・・ キャッチできるなら再開して残りのリクエストを処理する方がいいんじゃないかな リクエストキューとスレッド生存フラグは単一のロックで操作しないとまずいことになると思う 終了要求フラグは別のロックでも構わないけど、一緒にしとくのが無難かと 親側 lock { リクエスト投入 if (スレッド生存==false) { 子スレッド起動; スレッド生存=true } } 子側 loop { lock { if (終了要求) { スレッド生存=false; return } リクエスト取り出し if (もうリクエストないよ) { スレッド生存=false; return } } try { リクエスト処理 } catch { エラーメッセージを吐くとか } } たぶんこんな感じ?
終了してるかどうかはそのためのもの(WinならWaitForSingleObjectとか)で調べるでしょう。
>>565 スレッドが例外とかで突然死した場合はメイン側でWaitFor〜なりで捕まえて再起動するしかないけど、
リクエスト投入時の新スレッド起動判断をそれでやると、
その直前にリクエストがキューにないと判断したため自発的に終了しつつあるスレッドと入れ違いになる可能性が・・
>>564 おお、なるほど。そういう風にやればいいんですね。
>>557 だと、「いろいろな処理」中にisActiveがfalse、
かつリクエスト追加でフラグがtrueになるとスレッド二つになりますし、
タイミング的にスレッド消える危険もありますね。
それをテンプレにしていろいろ試してみたいと思います。
ありがとうございました。
俺ならこんな構造にする。 ・リクエストを出すスレッドはイベントループを持つ。 ・作業スレッドはリクエストキューと終了要求フラグを見ながら愚直に仕事をする。 ・作業スレッドが処理を1つ済ませたり終了したりしたら、 1回だけ呼ばれるコールバックを要求元スレッドのイベントループに登録する。 ・コールバックは要求元スレッドで走り、処理結果やエラーを通知する。 問題は、イベント待ちで寝ているときに目を覚まさせる方法が 既成のイベントループに必ずしも用意されていないこと。
毒を投げればいいだろ
基本的にスレッドはブロッキング操作があるようなものを非同期で行わせるために俺は使ってるから, イベントループとか使えないんだよね
一方、漏れは匙を投げた。
double pi=3.14159265358979823846; if((fp=fopen("PI.bin","wb"))==NULL) printf("\aファイルをオープンできません。\n"); else{ fwrite(&pi,sizeof(double),1,fp); fclose(fp); } C言語で↑のようにpiをバイナリファイルに書き込んで、 BZというバイナリエディタで開いたのですが”$-DT・ @”(文字部)と表示されました。 その後にfread関数でPI.binの内容をプログラム上で出力すると3.1415926……とさきほどの数字に限りなく近い数字できちんと表示されたのですが バイナリエディタで見ると変な文字に変わってしまうのは、何が原因なのでしょうか?これをバイナリファイルとして正しく見れる方法はあるのでしょうか。
ブルータス!お前もか!
576 :
デフォルトの名無しさん :2008/02/26(火) 01:43:14
>>572 原因はお前の頭が悪いこと。
そもそもスレ違い。
5日も前に誤爆だったと謝罪済みのレスに文句言う馬鹿って一体何考えてるの?
脊髄で書いてるのだろう
脊髄電脳化w
マルチスレッド対応の ハッシュリストのソースコードとかある?
ハッシュは速いのが売りなんだから、まるごとクリティカルセクションで包んでおけ
>>580 Javaのjava.util.concurrent.ConcurrentHashMap
同期処理なんてしなくてよし。 すべては運任せ。 マルチスレッドの邪神様に任せておきなさい。
コア1個ならなんとかなるさ、きっと
●5 コアは一個だが、HTだった
HTといえば、マルチコアの場合は異なるコア同士が同じキャッシュラインに アクセスしない方がいいけど、HTの場合は逆になるの?
マルチプロセッサ・マルチコア・HTで論理CPUが8個とかってどこのXEONだっけ?
AMDのです
>>588 キャッシュが共有の場合は、キャッシュラインが同じでもOK。そのほうが効率よい。
キャッシュが分かれている場合は、同じキャッシュラインへの書き込みは最悪になる。MESIプロトコルで具具ってみよう。
トランザクションメモリって、 JavaのAtomicReference#compareAndSetみたいなのじゃだめなの?
失敗したとき、その中でやったことは全部無しにしてくれるんだろうか?
>>593 良い場合もあるけど、例えば、複数のHashMapとかをatomicに操作したい場合は面倒じゃない?
マルチスレッドなくなってしまう。 今までがずっとCPUだと思っていたものは、実はスレッドなんで、。
596 :
デフォルトの名無しさん :2008/03/06(木) 02:46:25
Windowsでの条件変数実装の話題蒸し返したいので、俺の調査結果を晒してみる。
apr -> 再帰mutex非サポートぽい?簡潔過ぎるし、他にもバグあるだろ絶対。
yaneSDK3rd::LockObject -> すごく分かりやすい実装。再帰ロックしてのwaitにバグあり。修正は簡単。
boost::condition -> 複雑。完璧なのか?タイムアウト監視にシステム時刻使ってるのが嫌。
自前のC++ライブラリ構築して使ってるが、
yaneSDK3rdベースの実装からboostベースに交換してみようと思って
とりあえず、boost::xtime使ってる部分はGetTickCountに変えた。
システム時刻は某通信プロトコルでいつでも変更されてしまうので。
っつーか、clock()とかにもFILETIME使ってるのってどうなのよ・・・
boost実装に
>>473 のような問題が無いか検証しようとしてるが、
こいつのアルゴリズムは結構複雑で手強そうだ・・・
肝心のACEのソースはまだ読んでない。
条件変数の用途って 生産者/消費者的な使い方がかなりの部分を占めると思うんだけど、違うかな? そういう用途のみに限れば、IOCP使えば充分なんじゃないのかね。 キューにデータがあるときはカーネルに行かないって言明されてるし。
無知を承知で聞くけど、ユーザーモードに限って言えば 普通はCriticalSection一択じゃないの? CriticalSection自体がSpinCountの設定次第でカーネルモードにいかないようになってるから そのチューニングで大体の用途には間に合うと思うんだが。 VistaだとRead/Writeロックが実装されたから、そっち使ったほうが早いかもしれんけど。
Windowsはあまり知らないんだけど、Enter/Leaveしか出来ないの?
TryLock もバージョンが↓でなければできる
VC++Windowsアプリの質問です。 メッセージループを1つのスレッドに隔離しようと思うのですが、 PostQuitMessage(0)を別スレッドから単純に呼び出しても安全でしょうか? HWND g_hWnd BOOL g_Active; // g_Activeをクリティカルセクション内でやり取り BOOL fGetActive(); VOID fSetActive(BOOL isActive); INT WINAPI WinMain(...){ fSetActive(TRUE); g_hWnd = (ウインドウハンドル作成); メッセージループ用スレッド生成 while( fGetActive() ){ if(...) PostQuitMessage(0); } メッセージループ用スレッド後処理 return 0; } UINT WINAPI MessageLoop(...){ MSG msg; msg.hwnd = g_hWnd; while (GetMessage(&msg, NULL, 0, 0) > 0){ ... } fSetActive(FALSE); return 0; }
サブスレッドからアプリケーションを直接終了させる設計は変じゃないか。 メインスレッドに何らかのメッセージを送って、メインスレッドからアプリケーションを終了すればよいじゃない。 面倒なら、少々強引だが、PostThreadMessageでメインスレッドに 直接WM_QUITを送りつけるのも。あまりお勧めしないが。
ウィンドウはそれを作ったスレッドに結びついているよ
>>601 PostQuitMessageを別スレッドから呼び出すことは問題ないけど、
メッセージは、ウィンドウの作成元のスレッドにしか来ないよ
別スレッドでGetMessageしたかったら、そっち側でCreateWindowしないとだめ
605 :
604 :2008/03/16(日) 13:11:34
>PostQuitMessageを別スレッドから呼び出すことは問題ないけど、 って、ウソでした、カレントスレッドにWM_QUITを送るだけか PostThreadMessageで相手スレッドにWM_QUITを送ればいいかも
>>602-605 ありがとうございます。
MSG構造体へメッセージを送る際のデッドロックが心配でした。
>>602 >サブスレッドからアプリケーションを直接終了させる設計は変じゃないか。
ウインドウモードだと×からも終了させる場合があるのと、
メインスレッドのID取得が難しそうなので変えられなそうです。
>メインスレッドのID取得 プログラム開始時にメインスレッドから GetCurrentThreadId を呼んで、 メインスレッドのIDが取得して、それをグローバル変数にでも入れておけば良いかも。 それがいやなら、メインスレッドにくくりついている非表示ウィンドウを一つ作っておいて、 そこに向かって PostMessage して、メインスレッドにメッセージをポストするのも手。 windowsではよくある話。
もう一つ質問させてください。 メインスレッドがウィンドウを持ち、GetMessageのループをしていてかつ、 サブスレッドがメインスレッドのウィンドウにDirect3Dで描画している場合、 GetMessageとDirect3DがHWNDへのアクセス権をもめてクラッシュしますか?
swapchainでググれ
サブスレッドでバックバッファに書き込んだ後、 メインスレッドにバッファを転送するべきという意味ですか? うーん……
>>608 クラッシュしませんよ。
ただ、例外があって、ディバイスをリセットするときだけはディバイスを作成したスレッドからリセットを
コールしてあげないといけないからその点は注意。
メインスレッドでディバイスを作成した場合は、サブスレッドからはリセットは出来ない。
なので、もし、サブスレッドからディバイスをリセットする場合は、
まず、適当な自作ウィンドウメッセージをサブスレッドからメインスレッドのウィンドウに投げて、
メインスレッドのウィンドウがそれを拾ったらメインスレッド側から
ディバイスをリセットする。
Linux 2.6.21です sigwait()しているスレッドに他のスレッドからpthread_cancel()を実行してもスレッドがキャンセルされません sigwait()はキャンセルポイントのはずなのになぜ、と困惑しています うちの環境のみなんでしょうか もしくはLinuxの仕様?
613 :
612 :2008/03/19(水) 07:24:50
すいません、自分の勘違いでした
すいません。教えてください。 linux 2.6.20でpthreadです。 sched_get_priority_minとsched_get_priority_maxで優先度の 最大値と最小値を得たところ両方0でした。 これは優先度を選択できないということでしょうか。 優先度の最大値、最小値を得るのに使った引数は sched_getscheduler(getpid())で値は0でした。 よろしくおねがいします。 あ、あと書き忘れましたがlttng0.9.0のパッチを当ててます。
616 :
614 :2008/03/25(火) 21:04:25
ありがとうございます。 優先度を指定しよう思ったらSCHED_FIFOかSCHED_RRにしろということですね。 考えて見ます。
RTの付いたカーネルじゃないとダメじゃなかったっけ?
Numaで確保した共有メモリ内に pthread mutext仕込むと Numaで共有しているマシン間で 排他取れるの?
出来ないの?
教えてくれよw
POSIX準拠なら取れないとおかしいという結論になるはず。 「NUMAで確保したの共有メモリ」がPOSIX準拠かどうかまでは知ったこっちゃねぇ。
もし出来ないなら、アドレス空間が共有できてもうれしくないと思うんだが。 割と普通なOpteron複数搭載機ではまる人が続出しそう。
??
>>623 リード側と書き込み側の間でブロックしにくくなるんじゃないかな?
??
read同士でblockしない点が有用。
あるデータAをRWロックでブロックしてるとする スレッド1がAを読み込もうとしてるときに・・・ スレッド2がAを読み込むことがある スレッド3がAを書き込むことがある となっている2つの場合を考える もしスレッド1と2のみであれば、Aの値は不変のはずだから 1が処理中でも2は処理できる。 つまりRead同士ではブロックする必要がない しかし、1と2が処理中に3が処理しようとするとおかしくなる。 だから読み込み同士ではブロックないが 書き込みはブロックしないといけない。 これがReadロック。 逆に、3が動いているときに、1と2が読み込もうとしている場合は 3が終わるまでは1も2も読み込んではいけない。 スレッド4が書き込みをしようとしてたとして、これも当然ブロックしないといけない。 つまり排他処理するのがWriteロック。 これをMutexに置き換えると、Read同士でブロックしてしまう可能性があるので その頻度によってパフォーマンスが落ちることが考えられる。 しかし、とりあえず動かすことが重要であれば、置き換えるだけでも動く。
マルチスレッドで仕事量分割するための 手法説明している本ってないっすか?
VC6でマルチスレッドのアプリ作ってるんだがトラウマになりそうだ
マルチスレッド間で カスタムメモリアロケタ君を 書きたいけど基本的なロジックとか みんな何参考にしてるの?
633 :
デフォルトの名無しさん :2008/04/13(日) 23:00:37
すみません。 デバッグ中に、CPU帯域を独占してるスレッドを特定したいのですが。 なにかいい方法はありませんか? 開発環境はVisualStudio2005で言語はVC++です。
パフォーマンスモニタでスレッドIDごとの負荷率が出る。 スレッドIDはデバッガで一時停止のスレッドで見られる
>>634 ありがとうございます。
特定できました。
特定しますた
lock-freeアルゴリズムの 検証方法教えてくれよ どうやって正当性保障するんだよw あれ難しすぎだ
SPINみたいなのを使うんだろうか?
volatileで十分
原論文に検証あるだろ?
それが理解できないから、易しく解説して って言う話じゃないのかな。
数式での検証と 実装の検証は違うと思うのは俺だけw? 俺は頭が悪いんだろうなw
うん、頭が悪い。 「プログラムの正しさの証明」って言われて、 この証明が数学で言う証明のことだと理解できないタイプ。
実用性ない数式出されてもなぁ 後から付帯条件つきまくる数式 出されてもなぁ
マジで頭悪そう
ここも過疎ってるよなぁw
648 :
デフォルトの名無しさん :2008/04/23(水) 08:00:42
一覧に無いからだと思うあげ!
649 :
デフォルトの名無しさん :2008/05/02(金) 17:43:24
自作板にいるキチガイです。シングルスレッドで作成されてるソフトが
カーネルによってマルチコアにスレッド(タスクのことか?)が分散されると申しております。
このIDだけの発言では分かりにくいが、このスレにはシングルスレッドでもマルチコアのほうが早いと
のたまわってるキチガイがいます。
まだまだシングルCPUで頑張る人集合
http://pc11.2ch.net/test/read.cgi/jisaku/1169829748/ 800 Socket774 sage New! 2008/05/02(金) 08:31:32 ID:Aaj/7HlH
このスレのシングルコアユーザーは未だにWindows3.1を使ってるようだw
801 Socket774 sage New! 2008/05/02(金) 08:32:49 ID:Aaj/7HlH
プログラムのスレッドと
CPUが処理する単位のスレッドは
意味が違うw
802 Socket774 sage New! 2008/05/02(金) 08:42:42 ID:Aaj/7HlH
プログラムのスレッドはカーネルによってさらに細分化される
与えられたCPUタイムによってそれを1つづつ実行していく
大まかに2ブロックに分割されたとしよう
1コアが1ブロックを実行してCPU使用権が終了する
その時に2コアが暇をしてるので2ブロックに即座に使用権が渡される
つまり単純に2倍の処理性能になる
806 Socket774 sage New! 2008/05/02(金) 10:52:29 ID:Aaj/7HlH
いやだからマルチスレッドOSって時点で
実際のCPU利用率は半分以下なんだよ
どんだけがんばってもそうなの
シングルコアだったら100%使えるとかないからw
コアが2になるとより100%に近い状態になるわけ
一般に1.8倍だと言われる
MS-DOSやWindows3.1を使ってる人はシングルコアのが早いかもねwww
807 Socket774 sage New! 2008/05/02(金) 10:57:04 ID:Aaj/7HlH
>>803 ベンチマークのような単純処理の繰り返しではスレッドの細分化はほとんど行われない
ゲームみたいな大きなスレッドになると実際に4倍近くの性能を発揮する
>>649 頭のおかしな人というのはある程度の確率で常にあらわれるものであって、
そういう人がいるのはおかしいとか、説明して頭をよくしてあげよう等の考えは
全くの無駄だと思う。中身の入って無い枝豆同様ハズレとして無視するよりない。
いらいらする気持はわかるけどね。
コピペ君に応答する奴も馬鹿だな、まで読んだ。
osのタスク切り替え戦略によってはそうなるかもしれないけど、 普通は強制的な一定タイムスライスじゃないよね。 システムコール待つのにビジーウェイトでもしてると思ってんのか。
ほかのタスクや割り込み処理に割り込まれる可能性が減る(ほかのCPUに割り振られる)から 「遅くなりにくい」ということはいえるが 速くなることはないだろうなあ。 って件のスレで当人書いてるじゃん
1coreの時にOS側のタスクによるオーバヘッドが1%程度あったとすると 2coreならアプリの実行時間が1%短くなる程度なら有り得る
ゲームでならDirectSoundは別スレッドで動いてるので もうちょっと効果あるかもね。
例えばX11だと描画はサーバプロセスが行なうから結構効果がありますね。 でもそれをシングルスレッドアプリが速くなると言ってしまうとちょっと違うと思いますが。
よっぽど単純なプログラムでもない限り 完全なシングルスレッドなんてあり得ないんですけどねw
たとえばEXCELで 再計算処理が行われてる時にメニューを実行すると 再計算、描画、メニューの3つのスレッドが形成される
ビス太のユーザーランドスレッドの方針を分かって話してるの?
スレッドプールのはなし?
>>658 スレッドが生成されるかどうかと
並行実行するかどうかは別だぞ
OpenMP中で使ってるとか そんなんじゃねーのw
シングルスレッドでコンパイルするやつはいないだろw
それまでの話の流れとは関係ないが
「マルチスレッド対応ライブラリを使用する」と
「マルチスレッドで動作するプログラムにする」は全く違うのだが
まさかとは思うが、
>>665 はそういう意味じゃないよな?
当然、「コンパイラをマルチスレッドで動作させる」だよね?
一応触れておくと
Win32で普通にGUIプログラムを作る場合、明示的にスレッド関連の操作をしない限り
マルチスレッドで動くことは無い。
何故なら、メッセージキューが1スレッドに1つ作られるので
そこからのイベントで処理を記述する書き方だと、1スレッドにしかならないから。
(イベントハンドラでスレッド操作をすれば当然マルチスレッドも可能)
もちろん、カーネル内の処理(割り込み等)は別。
そういえば、Win9xのWinsock2の非同期処理は 内部的にスレッド作って擬似動作させてたんだっけ。 忘れてた。
>>666 メッセージキューも明示的に作る(作らせる)ものであって
スレッド作成=メッセージキュー作成じゃないよ。
> メッセージキューも明示的に作る(作らせる)ものであって 具体的にどうやって作るの?
MSDNのPostThreadMessageの所に書いてあるな
これのことかな... > その後、ポスト先のスレッドで、 > PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE) を呼び出し、 > このスレッド用のメッセージキューを強制的に作成します。 でもこれって、 > スレッドが Win32 のユーザー関数または GDI 関数のいずれかを最初に > 呼び出した時点で、システムはそのスレッドのメッセージキューを作成 > します。 ってことだよね。 あまり「明示的」とは思えないんだが...。
風が吹いたら桶屋が儲かるくらい暗黙的でなければ明示的
いや別にメッセージループに入ったからといって CPUを最後まで占有出来るわけじゃないのだ 途中で強制的に割り込まれる そうすると他のループに権利が渡されるだけだな マルチスレッドでコンパイルすると各メッセージループは完全に独立したスレッドになる だから既存のアプリもほとんどはデュアルコアの恩恵がある
おまえはそんなにメッセージループを作っているのか? 大多数のアプリはWinMainの中のGetMessage1つだけだと思うが
それと、「マルチスレッドでコンパイルする」の意味を具体的に説明しろよ
上の方は、プリエンプティブマルチタスクの解説で、4行目の 「他のループ」=「他のプロセスのメッセージループ」なのかなー と思って読んでいたが >マルチスレッドでコンパイルすると各メッセージループは完全に独立したスレッドになる え?
ちょっぴりエスパー能力を発揮して解読してみた。 普通、「メッセージループ」と言うと while (GetMessage()) { ... } の部分のことを指すと思うのだが おそらくこのヒトは、DispatchMessageで間接的に呼ばれるルーチン、 大抵は「WndProcの呼び出し1回」のことを 「メッセージループ」と呼んでいるような気がする。
だとしてもウインドウプロシージャがマルチスレッドで 並列実行されたりはしないと思うが。
もちろんその通り。 大丈夫、基本的な仕組みを理解してないのは、多分一人だけだから。
え? そうなん? メッセージループをマルチスレッドでコンパイルしたら 完全にプリエンプティブなマルチコアになるでしょ
だからその「マルチスレッドでコンパイル」って、何をどうすることなの?
一応、
>>666 の前半部に、候補としていくつか挙げてあるけど
・マルチスレッドライブラリを使用する(コンパイラオプションを設定)
・マルチスレッドで動作するようにソースコードを書き換えてコンパイルし直す
・コンパイル時にコンパイラがマルチスレッドで動作するオプションを使う(対応しているもののみ)
・その他
ところで、「プリエンプティブなマルチコアになる」って何?
「マルチスレッドでコンパイルする」「メッセージループがスレッドになる」に続いて
またまた第三者からは理解不能な言葉が出て来てるんですけど。
「マルチスレッドでコンパイルする」 そういえばVS2005から並行コンパイルができるようになったけど そのことかな。
>>683 知ってる単語を並べただけと言う疑惑も捨てがたい。(w
データを完全にシーケンシャルに 処理する必要があるのに スレッドの接続形態が 1-N-1って場合って どんな利点があるの?キュー作っても処理遅くなるだけじゃね?
メッセージの元になるイベントは、システム全体に対して非同期に起こるんだよ。 おまいのアプリ上だけじゃないし、処理終了を待って定期的に起こるわけでもない。
マルチスレッドでコンパイルする=MTsafeにするだろう
>>686 ここの人には「完全にシーケンシャル」の意味するところがわからないから、
その形態作った奴に聞いてみればいいんじゃね。
よくわからないけど、入力1、処理N、出力1みたいな感じだとすると、 最後の1を遊ばせないためには良いんじゃないかという気がする。 まあ何やるか次第だけど。
>>690 でもめちゃくちゃ排他制御かからないかなぁ?
常にシーケンシャルってことは前のデータ待って
処理しないといけないってことだろうし
コンパイラオプションのシングルとMTが具体的に何をしてるのかは知らないが MTにした時に各イベントは完全に非同期で発生する 並列実行してるのだと思ってるのだが違うのか?
いいえ。イベント発生は非同期ですが、受信が並列に行われる保証はありません。 # つーか、並列実行できるくらいならイベント機構はもっと簡略化できるわけで。
>コンパイラオプションのシングルとMTが具体的に何をしてるのかは知らないが コンパイラのヘルプ読めよ・・・
マルチスレッドでコンパイルといえばマルチスレッド実行されるのが当然だろ 何言ってるんだか
・マルチスレッド (対応のコンパイラ) でコンパイルといえば (コンパイラが) マルチスレッド実行... ・マルチスレッド (オプションをつけた状態) でコンパイルといえば (生成されたプログラムが) マルチスレッド実行... 日本語難しいアルネ。
最近のコンパイラはマルチスレッドで動作するプログラムを勝手に生成してくれるの?
MT対応ライブラリをリンクするだけじゃね OpenMPとか一応あるけど明示的にディレクティブを書かないといけないし
それはライブラリの使い方次第だろう。 MT-safeになるだけっていうのとはまた違うし。 なんかレベルがよく分からない抽象的な話しかないのは気のせいか。
>>697 コンパイラ自体は何もしないけど
MFCとかのフレームワークがするんでしょ
私はいつものようにMFCでプログラムを組んでいた 当然のごとくMTをコンパイラオプションに指定した ある日、子ウィンドウから親ウィンドウにある関数を実行する必要性が出てきた 私はPostMessageでオリジナルのイベントを実装することを思いついた そこには処理Aと処理Bという2つの関数が存在した 処理Bは処理Aの結果を利用するものである 処理B単体で実行する場合もあるのでこの2つは独立していた 私は当然のごとく各イベントはシーケンスに処理させるのだと思い込んでいた メッセージA、メッセージBと順番に親ウィンドウに送信する するとどうだろうか プログラムは例外エラーを発生させて画面から消えるではないか 私は挙動を調べるべく調査に乗り出した そしてついにその原因を突き止めた この2つの処理は同時に実行されている
非同期のPostMessageじゃなくて同期のSendMessageだったっけ、そういうのなかった? winapiから遠ざかりすぎてワスレタ。非同期メッセージ通信なのだから、 >各イベントはシーケンスに処理させる って前提は、キューに入れられた順番はあるけど cpuが空いていればキューから取り出してすぐに実行されるってこと?
内部的にSendMessage使ってる関数でデッドロックしたことがあるのでマルチスレッド怖い
デッドロックはアナライザで一発で見つかるから楽。 問題はコンディションレースだ。
>>701 MFCをコンパイルするときは/MLオプションを
受け付けなかったと思ったがどうだっただろう。
/MD と /MTの切り替えは問題なく出来るはず。
さらにVS2005からは/MLは廃止になっている。
一応説明しておくと
/MLはシングルスレッド用CRTライブラリのスタティックリンク
/MTはマルチスレッド用CRTライブラリのスタティックリンク
/MDはMSVCRT.DLL(版によって名称の差異あり)へのダイナミックリンク
メッセージキューは必要に応じてスレッドごとに生成される。
自他スレッドやOSから発行されるウインドウメッセージはメッセージキューで並列化され、
メッセージループで読み出されることによってその後のウインドウプロシージャの処理は
メッセージループのスレッドで実行される。
つまりマルチなのはキューまでで後は単一のスレッドで実行される。
ただし単純にシーケンシャルに実行されるわけではない。
キューはプライオリティキューであり順番が入れ替わることがある。
ウインドウプロシージャ内でメッセージキューに関係する命令を使った場合、
現在のメッセージの処理を一旦中断し別のメッセージに実行権を譲渡することがある。
>>701 はこの辺を並列で実行されたと誤認してるものと思われる。
どうしてもマルチで動作してると言い張るつもりなら、
ウインドウプロシージャにスレッドIDの変化を調べるルーティンを入れて
変化が認められるか調べるのが一番だと思う。
>>706 2行目訂正
誤)メッセージキューで並列化され
正)メッセージキューで直列化され
>>701 新しいスレッドを作らない限り同時に実行は無いよ。もっとよく調べてみよう。
WndProcがマルチスレッドに動くなら そこらじゅうMutexやらCritical Sessionだらけになる予感 もちろんVolatile論争もこのスレ的にOK
同期コストで逆に遅くなりそうだな。
どうせCSocketみたいな内部でPeekMessageで回してるのを見て 同時実行されてると思い込んでるだけでしょ。
何の技術もないんですが、気になってることを質問させてください。 マルチコアプロセッサでマルチスレッドのプログラミングをする時って スレッドを、ポンポンって作って、後はOSとかが暇にしてるコアに 仕事を割り振ってるんですか? それとも、プログラムの側で、「この処理はお前がやれ」ってマルチコアの 特定のコアに指定して割り振るんですか? 調べてみたら、どうも前者っぽいんですが、気になって昨夜は2時間くらい 布団の中で寝れませんでした。お願いします、教えてください。
>>712 何も指定しなければOSが自動的に割り振る。
指定すれば割り振ることができる。
だからどっちともいえる。
>>713 ありがとう。これで今夜はゆっくり寝れる。
もうひとつ聞きたいこと出てきました。
指定する場合ってどうやるのか、キーワードだけでも
教えていただけると有り難いです。
>>715 あーりーがーとー。
いろんなキーワードで調べてたけど
ずっと見つからなかったものが、ようやく見つかった。
感謝します。
お邪魔しました。
>>716 Linuxだとtasksetってコマンドで簡単に設定できるので便利。
>>717 おぉ。寝る前に念のためにきてみたら、またいいこと知った。
ありがとねー。
719 :
デフォルトの名無しさん :2008/05/21(水) 17:41:08
質問させて下さい。 WindowsでGUIから何らかのアクションでスレッドを起動し、 ESCキーを押下でメッセージボックスを表示して、 スレッドの実行を中止できるようにしたいと考えています。 こんな風に↓ case IDM_KEY_ESCAPE: { if (thread.suspend()==0) { if (MessageBox(hwnd, "", ""),MB_OKCANCEL)==IDOK) { thread.terminate(); } else { thread.resume(); } } break; } で、以下のようなスレッドクラスを作成しました。 (つづきます)
720 :
719 :2008/05/21(水) 17:42:31
class Thread { HANDLE hthread_; unsigned int id_; void run(void) { /* 具体的な処理 */ } public: void start(void) { hthread_ = (HANDLE)_beginthreadex(NULL, 0, Thread::entrypoint, this, 0, &id_); } DWORD suspend(void) const { return SuspendThread(handle()); } DWORD resume(void) const { return ResumeThread(handle())); } static unsigned int WINAPI entrypoint(void* instance) { thread_t* p = static_cast<thread_t*>(instance); p->run(); _endthreadex(0); CloseHandle(p->handle()); p->hthread_ = 0; return 0; } };
721 :
719 :2008/05/21(水) 17:43:00
しかし、実際に使ってみたところ、ESCキーでメッセージボックスを表示すると、 たしかにスレッドの処理は中断するのですが、 タスクマネージャを見ると中断している間も実行メモリが数KBずつ増えていくのです。 それで中断したまま(メッセージボックスを表示したまま)しばらく放っておくと、 タスクマネージャに表示された該当プロセスのスレッド数が1つ減ります。 (つまりGUI起動時のスレッド数になる) そこでメッセージボックスのOKを選択してスレッドを終了すると、 さらにスレッド数が1つ減って、壊れた振る舞いをするという具合です。 とりあえずスレッドクラスについて質問したいのですが、 ↑は変な実装ではないでしょうか?それから使い方も問題ないでしょうか? OS:Windows Vista x64 言語:C++ 環境:Visual Studio 2008
722 :
719 :2008/05/21(水) 17:46:25
すみません。
>>720 のthread_tはThreadの間違い、
p->handle()はp->hthread_、それからterminateメソッドが抜けていました。
void terminate(void) {
TerminateThread(hthread_, 0);
CloseHandle(hthread_);
hthread_ = 0;
}
}
TerminateThreadで終わらせたとき、run内で動的に確保されていたリソースはどうなるでしょうか。 それと、entrypoint内_endthreadex(0)の後に記述した処理は実行されないと思うのですが。 あとは知らん。
724 :
719 :2008/05/21(水) 18:18:12
>>723 どうも。_endthread(0)でスレッドを終了したら、
自動的にentrypointから抜けてしまうのでしょうか?この辺、自信ありません。
(entrypointから抜けるときに_endthreadが呼ばれるというのはMSDNに書いてありましたが…)
あとrun内でのメモリの確保は全部boost::shared_ptrを使ってるので問題ないと思います。
いずれにしてもsuspend中に問題が発生しているわけで…。
mallocの中でsuspendしたら・・・とか思うと怖いな 何が起きても不思議ではない気がする
>>722 TerminateThreadの説明読んだ?
こんなおっかねーAPI俺は使ったことないぞ。
強制終了に相当する処理だよ。後始末なんか何もしない。
727 :
719 :2008/05/21(水) 18:59:04
TerminateThreadが危険というのは知識としては知ってますが、 そこに至る前のSuspendThreadの時点で問題が起きているようです。 仮にメッセージボックスでキャンセルを選んで、 TerminateThreadではなくResumeThreadを呼んだ場合でも処理が壊れるのです…。
728 :
719 :2008/05/21(水) 19:03:28
>>725 スレッド内で動的にメモリを確保するのは一般的なことだと思うのですが、
その場合にSuspendThreadを呼ぶタイミングが問題になるなら、
Suspend/ResumeThreadというのはものすごく使いにくい関数な気が。
TerminateThread()とか_endthreadex()は、 「呼ばれたらスコープを抜けてローカル変数の解体処理をして…」 なんてことは、一 切 や っ て く れ ま せ ん 。 稼動中のPCの電源を無造作に切るかのようにスレッドの処理を打ち切ってくれます。 shared_ptrのデストラクタなんか呼ばれるわけが無いので、メモリリーク必至です。 で、知っているくせに何でそんなふざけたコード書いてんの?
730 :
719 :2008/05/21(水) 19:08:11
>>729 あ、デストラクタも呼ばれないんですか。それは知りませんでした。勉強になりました。
で、なんでこういうコードを書いているかというと、
危険だというTerminateThreadを何に置き換えるかは後で考えるとして、
とりあえずSuspend/Resumeの部分を実装するために書いたコードなわけで。
732 :
719 :2008/05/21(水) 19:19:42
>>731 なるほど。その"This function is ..."の1文でいろいろ吹っ切れた気が…。
Suspend/Resumeの機能を実装したければ、外からスレッドに何かシグナルを送って、
スレッド自らの手でSuspendする必要があるわけですね。
SuspendThreadはその部分をよきに計らってくれるものだと勘違いしていました。
どうもありがとう〜。
まあ精進してちょ。
ふつーはイベントを待つ。
グローバルにスレッド管理用のフラグを用意する スレッド起動時にこのフラグを1にセット スレッド内で定期的にこのフラグを監視し0になったら途中で終了する メッセージボックスでキャンセルされた時はこのフラグを0にするだけ
マルチスレッドだとスタック領域が別になるから グローバルで取ったフラグ用変数のポインタをスレッドに最初に渡すのだよ
別にクラス内のローカルな変数でもいいんだけどね その時はクラスのポインタを渡すのだよ クラス定義を組み込むのを忘れないでね
あとvolatileも
c/c++のvolatileはいろいろあるから、 ちゃんとmutexなどの同期オブジェクトを使うことをすすめる。 ただwindows限定ならvolatileにメモリバリアの意味があるのだっけ?
> c/c++のvolatileはいろいろあるから、 > ちゃんとmutexなどの同期オブジェクトを使うことをすすめる。 もしかして volatile 変数で同期とろうとか思ってる?
荒れる予感
>>739 メモリバリアの意味はない。
ただ、IA32はコヒーレントキャッシュだから、volatileだけでも
大して問題がないだけ。
ていうかこのケースは知らないが もし「ループを一周余分に回すことになっても問題ない」という 厳密な同期が必要ないものならば、volatileで済むケースはある。 そんなに多くは無いが。
>もし「ループを一周余分に回すことになっても問題ない」という >厳密な同期が必要ないものならば、volatileで済むケースはある。 むしろ今回のケースでは一周分余分に回すのがアウトという状況が考えにくい。
一周分余分に回ってアウトなら最初から排他なりセマフォなり入れるしな
746 :
719 :2008/05/25(日) 16:06:04
結局↓のようなクラスにしました。今のところ問題ありません。 class Thread { HANDLE hthread_, hevent_; unsigned int id_; bool cancel_; void run(void) { while (1) { /* 具体的な処理 */ if (cancel_check()) { return; } } } public: Thread(void) : hevent_(CreateEvent(NULL, TRUE, TRUE, NULL)), cancel_(false) {} ~Thread() { CloseHandle(hevent_); } void start(void) { hthread_ = (HANDLE)_beginthreadex(NULL, 0, Thread::entrypoint, this, 0, &id_); } void cancel(void) { cancel_ = true; SetEvent(hevent_); } void suspend(void) { ResetEvent(hevent_); } void resume(void) { SetEvent(hevent_); } bool cancel_check(void) { if (cancel_) { cancel_ = false; return true; } WaitForSingleObject(hevent_, INFINITE); return false; } static unsigned int WINAPI entrypoint(void* instance) { thread_t* p = static_cast<thread_t*>(instance); p->run(); CloseHandle(p->hthread_); p->hthread_ = 0; return 0; } };
run()内で例外投げられたらまずくね
kwsk
OoOの問題じゃないかなと思ったり。
UOがどうしたって?
752 :
匿名 :2008/05/30(金) 15:12:16
ばか?
生成したスレッドがmallocをしている最中に SuspendThreadするとどんな問題が発生しますか?
mallocの中で排他制御しているだろうから、他のスレッドがmallocを呼 ぶと返ってこなくなるかも。
mallocがマルチスレッド対応版だと仮定すると、 ヒープ管理データへのアクセスの排他のために mutexを握るタイミングがあるはず そのタイミングでSuspendされると ほかのスレッドがmalloc/free関連の処理をしようとして mutex握れなくてずっと待ちに入る newがmallocをベースにしているならnew/deleteも はたから見るとハングアップに見える
>739 C#のvolatileはメモリバリアの意味もあるよ。 C/C++じゃないよ。
ふ〜ん
MSDNのSystem.Threading.Thread.MemoryBarrierの説明が微妙でわかりづらい >MemoryBarrier は、複数の Intel Itanium プロセッサを使用しているシステムなど、 >ウィーク メモリ オーダリングを採用したマルチプロセッサ システムでだけ使用します。
質問しようと思ったら
>>746 に俺が・・・
この場合だとentrypoint内でCloseHandleしてreturn完了後にendthreadex呼ばれるという
挙動であってるのかな?で、ハンドルも問題なく閉じられるのか?
>>746 は無茶苦茶だろ。
とりあえず思ったこと。
・startで生成したhthreadを別のスレッドでcloseするのが変。
代入前にサブスレッドが終了したらアウチ
・startが2回呼び出されたときのガードは当然してるよな
・とりあえずcancel_はvolatileにしとけ。即座でなくても
そのうちtrueが伝わるだろう
・cancelは変数で一時停止がEventだが、どちらかに統一しとけ
・entrypointはprivateにしとけ
・entrypintでrunの例外処理しないとendthreadexが呼ばれない
・キャストはreinterpret_cast使え
・サブスレッドの実行を管理するThreadとサブスレッド処理のクラスを
どうして同じにするかな。runとcancel_checkはThreadと別クラスに分離した
方がよいと思う
・_beginthreadexとCreateEventのエラーチェックしろ
・サブスレッドが完了したか調べる関数がほしい
あと、Threadがスコープから抜けるとrunのthisが無効になる設計は嫌いだ。
Threadのデストラクタでjoin(WaitForSingleObject(hthread_))すべきだと思う。
呼び出し側が責任を持って事前にcancelを呼び出し、それを怠ったら
不正メモリアクセスでなく永久waitになった方がマシ
761ですが・・・俺の場合は ・コンストラクタで生成してるけどサスペンドで作成してるから、代入前に終了はないはず ・bool使ってやってます。全体的にこれらの操作はミューテックスで排他してるんですが、 それで十分なんでしょうか? ・ ・ ・なってます ・なるほどやりました。 ・なるほどやりました。 ・実行管理がThreadクラスで、サブ処理がRunnableインタフェースを被ったクラスのrun()メソッド です。Thread自身もRunnableインタフェースを継承してます。(ただしrun()は空) ・失敗してたら何もしないようにしただけです・・・ ・void Thread::join(DWORD timeout){ if(tb == NULL)return; ::WaitForSingleObject(tb->hThread,timeout); } これで十分でしょうか?
764 :
デフォルトの名無しさん :2008/06/08(日) 13:05:59
MSが言っている"アラート可能な待機状態"とはどういう状態のことですか?
何らかのイベント?とかで待機を中断できるってことじゃね?
746みたいな事をやるときのboost::threadの楽さと言ったら…。
767 :
デフォルトの名無しさん :2008/06/08(日) 13:12:39
それは、普通の待機状態とアラート可能な待機状態の違いは スレッドプロセスが__cdeclか__stdcallかの違いである ということですか?
768 :
デフォルトの名無しさん :2008/06/08(日) 13:24:31
違いますね。APCとか理解できません。
>>764 重複I/Oを使うときにのイベント待機に使う。
>764 SleepExとかWaitFor〜Exで、bAlertable=TRUEの状態で寝てるとき
>>763 > ・コンストラクタで生成してるけどサスペンドで作成
→ 論理的に正しく動くのはわかったけど、わかりづらくない?
ハンドル作成したスレッドが(デストラクタあたりで)closeするのが自然だと思うんだが。
> ・bool使ってやってます。全体的にこれらの操作はミューテックスで排他してるんですが、
→ startの多重チェックに同期は要らない。なぜならstartは
一つのスレッド(メイン)からしか呼び出さないのが前提だから
> Thread自身もRunnableインタフェースを継承してます
それはJava APIと同じ設計だけど、APIの設計ミスだと思う。
各クラスの役割は最低限にしようよ。
Runnable: サブスレッドで実行する処理のクラス(主にサブスレッドで使用)
Thread: Runnableのスレッド実行を管理するクラス(メインスレッドから使用)
実行制御でもcancel/suspend/resumeは処理固有なのでRunnable側に実装。
スレッドハンドルはスレッド実行管理の話だからThreadでclose。
> void Thread::join(DWORD timeout)
できれば戻り値をboolにして
DWORD status = ::WaitForSingleObject(?????)
if (status == WAIT_ABANDONED) throw ????;
return status == WAIT_OBJECT_0; // 完了したかどうか
かな。
JavaのThreadにケチつけるアホがいるスレはここですか?
JavaのThread implements Runnableは失敗だろjk
Treadクラスの継承が失敗だろ
>>775 ○Mutex
・LockでWaitForSingleObjectの戻り値確認しろ。タイムアウトしたら大変なことになるぞ
○Thread
・何でthread_bodyの定義を書く前に変数宣言できるんだ?コンパイル通った?
thread_bodyのスマートポインタでないとマズくね?
・start内に例外発生するとマズい場所が多すぎ。line 60,61,62,63,64,68
・isAliveのロジックが間違ってる。スレッドがSTILL_ACTIVE返したら区別つかない。
WaitForSingleObject(スレッドハンドル) == WAIT_OBJECT_0 で判断しろ
・ThreadProcで(const Thread&)のキャストは要らないでしょ
・マップ操作前後のロックタイミングはこれでいいと思う
・suspend/resumeのロックはこれでいいと思う
・joinでWaitForSingleObjectの戻り値確認して
・isAliveにロックは不要
・クラス設計が変。currentThreadの返したThreadは何だ?
実際のrunと関係ないrunを持つThreadをnewして返すのは絶対変だ
・Runnableとt_threadの使い分けをもう少し整理して
・ヘッダ名見直せ。<cstdio><windows.h><process.h><map><cstdio><sstream>
> tb=thread_pool_for_runnable[target];//既にあるRunnableの時はそれを使う
? エラー返すべきでは?
あと、ミューテックスのロックはヘルパークラス作れ。
コンストラクタでミューテックスを受け取ってロックし、デストラクタでアンロック。
でないと途中で例外が発生したときにいちいち対処できない。
> もう全然うまくいかないので
何がうまくいかない? 何となく動きそうだが。
コンパイルエラーとか言ったら殺
今携帯なんで、後で詳しく見ますが、うまくいかないというのは これで画像読み込みをしたときに画像読み込みが出来なかったりするんです 実験中には終了時に不正アクセスみたいのが出たり…
777が優しすぎる 俺が男なら惚れてたね
俺は男だから惚れた
じゃあ掘れるのか
惚れたけど掘れない。
783 :
719 :2008/06/10(火) 20:22:05
いやぁ、勉強になるなぁ…。
質問があります pthreadでは途中でスレッドをキャンセルする場合 pthread_cancelを遅延キャンセルでコールして、 クリーンナップハンドラでリソースを開放するという方法が考えられますが、 C++では実行環境(gcc,glibc)によって、クリーンナップ内でオブジェクトの デストラクタが呼ばれなかったり、例外処理が行われないなどといったことがあるみたいですが、 「C++ではこのようにしてpthreadを中段させるべき」といった 定石的手法が確立しているのでしょうか? できればURIなど情報源などもあれば教えてください。 【OS】 Linux2.6 【言語】 C++ 【実行環境】 RHEL5(pthread) 【その他突起する事項】 「RHEL5の中のライブラリならサポートしてるので気にするな」ってのは無しで
外から中断なんかしない。 当たり前すぎて泣けてくる。
>>784 安全に中断させる方法なんて存在しない。
だが、スレッドのエントリ関数のreturnを実行して正しく終了させる方法はいくらでもある。
> 「C++ではこのようにしてpthreadを中段させるべき」といった > 定石的手法が確立しているのでしょうか? 中断通知機構は自分で独自に実装。必ずエントリポイントの関数まで 戻るようにする。 異常時に終了するため、終了用の例外クラスを作成。エントリポイントのみ でcatchし、他はクラスに対し例外中立なコードを書く。 ソースは俺。
>>778 joinせずに終了したか、Thread,Runnableのメモリが誤って解放されたのでは
スレッド止めてプロセスにする
790 :
777 :2008/06/11(水) 21:51:22
アクターモデルって奴の C++とかjavaとかでのサンプルない?
761です
>>790 ブワッ!なんと言うやさしさ・・・やっと時間が取れたので、777を元に修正してたら、なんという
でも俺はウホじゃないです。すいません
(const Thread&)のキャストですが、こうしたらローカル変数の寿命がどうたらで1個分生成・破棄の
コストが浮くかなあと思って付けたんですが・・・まぁ、確認もせずにつけたので効果はいざ知れず
> currentThreadの返したThreadは何だ?
この関数を実行したスレッドがスレッドプール内に存在すれば、そのスレッドを操作する
Threadオブジェクトを返します。
既存のRunnableの時再利用するのは
Hoge(){
Thread th(this);th.start();
}
~Hoge(){
Thread(this).join();
}
とすることに憧れていたからです・・・。つまり俺がちょっとおかしいのです
pthread mutexで 読みスレッドが2人 書きスレッドが2人 といる場合、rwlock使うと読んでる間に 書き込もうとしてもロックされる?
pthreadは知らないけど一般のReader-Writer-Lockなら排他制御されなぎまずいんじゃね。 Readerのみの場合に排他されないんだと思う。 Reader vs. Reader → 排他されない Reader vs. Writer → 排他される Writer vs. Writer → 排他される
Pthreadもそうだったと思う Man読みゃいいんだけどね
スレッドAがrdlockする スレッドBがwrlockしようとする(が、rdlock中なのでブロック) この状態の時に、スレッドCがrdlockしようとすると 1.スレッドCがrdlockを取得(Aと共存)出来る 2.スレッドB(ロック獲得優先権がある)の処理終了までブロックする 一般的にはどうなる? ・一般的に、rwlockと呼ばれるものの動作として決まっている(どっち?) ・pthreadの標準として決まっている(どっち?) ・何も決まってない(実装依存)
おー、thx
800 :
777 :2008/06/13(金) 23:54:51
>>761 これ以上はスレが荒れるといかんのでやめてくれ。これが最後だ。
・サブスレッド実行したままmain終了するな
・vector<image>は大丈夫か? imageのコピーコンストラクタ呼ばれまくるぞ
・「LockでWaitForSingleObjectの戻り値確認しろ」って言ったよな? 聞いてる?
同期オブジェクトをロックしたまま自身をサスペンドしたら誰がロック解除するんだ
→ 罰として、Win32APIの全呼び出しをエラーチェックしろ
→ 罰として、全行の間にデバッグ用のprintf入れて何が起きてるか理解しろ
→ 罰として、「これはmainスレッドから呼ぶ」/「これはサブスレッドから呼ぶ」
のコメントを全関数に書け
→ 罰として、これから一年 SuspendThread の使用を禁ず。危険すぎる。
お前のやりたいことをするにはpthreadの条件変数を使うのが自然だが
Win32には無いのでとりあえずresume/suspendを ↓ に書き直せ
class x {
HANDLE suspend_lock;
protected:
void i_am_Thread_and_i_will_wait_until_someone_resume_me()
{ ::ResetEvent(this->suspend_lock);
::WaitForSingleObject(this->suspend_lock, INFINITE); }
public:
x() : suspend_lock(::CreateEvent(NULL, TRUE, FALSE, NULL)) {}
void run() { /* .......*/ }
void i_am_main_and_i_resume_Thread()
{ ::SetEvent(this->suspend_lock); }
};
なんて優しい罰だ!
スレッドを作成して、そのスレッド内でエラー用のMessageBoxや 設定変更の為のプロシージャを起動させると CPU使用率が100%になってしまいます。 これってどうやって回避すればいいのでしょうか?
簡単にすると、スレッドのメッセージループにおいて――― while(0) { switch(message) case WM_KEYDOWN: MessageBox(NULL, "メッセージボックスの表示", "test", WM_OK); break; } ……という場合、メッセージボックスを表示させるとCPU使用率が100%になるんです。 メンバにコールバック関数を組み込んだクラスでダイアログボックスを表示させても同様です。 回避方法ってないもんでしょうか。
スレッド生成して呼び出し元が先に終了しても、スレッドは動き続ける?
WAIT_ABANDONEDってタイムアウトを設定してても WAIT_OBJECT_0やWAIT_TIMEOUTが返らずにただ非シグナルになったことだけを返しちゃうの?
ミューテックスを獲得できた結果、非シグナルになったのでは? WAIT_OBJECT_0 と同じに扱えばいいと思うけど
>>807 ありがとう。日本語苦手なんだよね・・・。
>>804 そのコードから読み取れるものは何もないし、おそらくMessageBoxうんぬんは全く関係ない。
スレッドのメッセージループというのは、スレッドをUIスレッドにしてるのか?
それともPostThreadMessage用のGetMessageだけの簡易版なのか?
デバッガで追えばわかるでしょ。デバッガが無理でもログ出せば 何が起きてるかわかると思うが。 グローバルにFILE* f宣言してWinMainの最初でfopenしてfprintfでログ出す。 そのぐらいは確認してから訊いて欲しいなぁ。
813 :
719 :2008/06/15(日) 03:06:12
boost::thread使うことにしました。で、suspend、resume、cancelを実装したいのですが、 以下のような使い方で間違っていないでしょうか? 気になるのは※1の箇所のmutexが何のためのmutexかよくわからない点なんですが…。 case IDM_KEY_ESCAPE: { // エスケープキーを押したらサスペンド runnable->suspend(); if (MessageBox(hwnd, TEXT("Quit the thread?"), TEXT("CANCEL"), MB_OKCANCEL|MB_ICONQUESTION|MB_DEFBUTTON1)==IDOK) { runnable->cancel(); } // OKでスレッド中止 else { runnable->resume(); } // CANCELでスレッド再開 break; } Runnable::Runnable(void) : cancel_(false), suspend_(false), is_running_(false) {} void Runnable::suspend(void) { suspend_ = true; } void Runnable::resume(void) { suspend_ = false; condition_.notify_one(); } void Runnable::cancel(void) { cancel_ = true; condition_.notify_one(); } void Runnable::operator()(void) { is_running_ = true; while (1) { if (suspend_) { boost::mutex::scoped_lock lock(mutex_); condition_.wait(lock); } // ※1 if (cancel_) break; ...処理... } is_running_ = false; suspend_ = false; cancel_ = false; }
泥沼の予感
>なんて優しい罰だ! 純愛系ソフトSM?
まともに書けない(or書きたくない)香具師はOpenMPを使ってろよ。 下手な実装よりもよっぽど巧く動くし簡単だぞ。
>>805 Windowsの場合、全スレッドが終了するまでプロセスが終了しない。
でもC Runtimeライブラリの後始末とか走るかもしれないので危険かも知れない。
Javaは知らん。
.NET Frameworkの場合、スレッド属性を「フォアグラウンド」/「バックグラウンド」
の切り替えが出来て、バックグラウンドにした場合はMainが終了するとサブスレッドも
終了。
今回のコードでは不要だけど、制御の切り替わりの時に他の変数も一緒に変更して あげなきゃいけないようなときに、notify_one側とwait側の両方で該当箇所の前後を含めて 排他制御するため、だと思う。
>>817 javaはデーモンスレッドじゃないスレッドがいなくなったら終わる。
Thread.setDaemonで切り替える。
.NETのバックグラウンド相当かな。
820 :
719 :2008/06/16(月) 16:07:59
>>818 今回のコードに関しては意味的には不要ということであってるわけですね。
将来的に必要になってくる気がしますけど。
ありがとうございました〜。
821 :
818 :2008/06/16(月) 22:29:34
訂正。
>>813 はsuspend_の変更とロックをアトミックに行わないとだめな気がする。
void Runnable::suspend(void) { boost::mutex::scoped_lock lock(mutex_); suspend_ = true; }
void Runnable::resume(void) { boost::mutex::scoped_lock lock(mutex_); suspend_ = false; condition_.notify_one(); }
while (true) {
{
boost::mutex::scoped_lock lock(mutex_);
if (suspend_) { condition_.wait(lock); }
}
>>802 ですが、自己解決しました。
メインのメッセージプロシージャにおいて下記のようにしていたことが原因でした。
switch(message)
{
case WM_KEYDOWN:
(中略)
default:
PostThreadMessage(MainThreadID, message, wParam, lParam);
return DefWindowProc(hWnd, message, wParam, lParam);
}
このため、スレッド内で別のメッセージループを持つ関数を起動させると
CPU使用率が100%になっていました。
お騒がせしました。
823 :
719 :2008/06/18(水) 21:32:49
>>821 親切にどうも。その後
>>813 ではうまくいかないタイミングがあり、
>>821 にあるようにsuspend、resumeにlockを追加したのですが、
whileの部分を
if (suspend_) {
boost::mutex::scoped_lock lock(mutex_);
condition_.wait(lock);
}
としていました。これだとうまくいかず考えてたんですが
>>821 で解決できそうです。
>>822 すまないがゆとりの俺には理解できなかった。もう少し説明プリーズ。
メインスレッドのメッセージループでサブスレッドにメッセージをPostする
ことと、サブスレッドでメッセージボックスを出すことで、どうしてCPUが100%なの?
せいぜいメッセージボックスが何度か再帰呼び出しされるだけに見えるが。
>>800 のvoid i_am_Thread_and_i_will_wait_until_someone_resume_me()って
この関数を呼んだスレッドが停止しちゃうんだよね?やっぱり変なタイミングで
スレッドを停止しないようにってこと?
タイミングの問題じゃないよ。単に実装が間違ってた。 元々のコードに書いてあったのは「サブスレッドが自分の処理を終えると待ちに入る」こと。 ところが、メインスレッドがサブを再開させようとするとデッドロックするバグがあったので そうならないように書き直した。 「誰かが起こしてくれるまで眠り続ける薬」を、部屋の内側から鍵かけて飲むような 作りになってた。
>>826 あ、気になってたんですがstaticオブジェクトのデストラクタってどのスレッドが実行してるんでしょうか?
C++の言語仕様はスレッドの概念が無いので規定がない。 気になったらまず確認しろ。仕様は不明でも特定の処理系の実装はわかる。 #include <windows.h> #include <cstdio> struct x {~x() {std::printf("%d\n", ::GetCurrentThreadId());}} obj1; int main() {x();}
スレッド関数内で作った static オブジェクトのことじゃないのか?
exit() を実行したスレッドじゃないか? と当てずっぽうに言ってみるが
>>830 Microsoftはそーみたいだね。その関数の存在忘れてたわ。
>>829 exitのケースを除いて、スレッド関数内のstatic変数をそのスレッドで
破棄したら言語仕様を満たせなくなるんでない?
破棄のタイミングはmain関数より後なんで。
そもそも「スレッド関数内で作った static オブジェクト」ってなんだ?
スレッドに渡すコールバック関数内にstaticなオブジェクトがあるという話しだろ
それを「関数内で作った」って言うのか? もし本気でそう思ってるなら、もうし少し static オブジェクトについて 勉強したほうがいいんじゃないか。
文法上のレベルとコンパイル後のレベルを比べられてもなぁ…
俺には834の方が何を意図しているのかよく分からん。
なんとなく void hoge(){ static int x; } みたいな関数があるとき、関数内に書いた≠関数内で作った、って言いたいんじゃないかと想像
いろんなスレッドがhogeを呼び出してなんどもコンストラクタが呼ばれるんですね わかります
dataが今456000000000個あります。 これを312台のマシンで分割して計算したいのですが 何を勉強すればいいのでしょうか?
MapReduce
マジレスするとRuby
スレッドというか分散処理
Erlang
>>839 スレ違いであるということを勉強したらいいと思うよ。
>>836-837 >>837 の例だと、x は、hoge() に入る前から存在するんだから
「関数内で作った」と言われるとすごい違和感があるんだが、
俺の感覚の方がおかしいのかなぁ。
>>838 「関数内で作った」とか言われたら普通そう思うよな。
関数内のstatic変数が初期化されるのは、初めて実行されるときじゃなかったか? そういう意味なら「関数内で作った」と言ってもそれほど変だとは思わないな。
>>846 > hoge() に入る前から存在するんだから
しないよ。それは規格(ISO/IEC 9899:1999, ISO/IEC 14882:2003)で決まってる。
void thread_entry()
{
static struct x = some_func();
}
xは最初に制御がここを通るときに生成される。
あ、「生成」っていうのは実装としてメモリが確保されるとかじゃなくて、 概念的にオブジェクトが利用可能な状態になるってことね。
void in_thread_func() {
static std::string("あいうえお");
}
も同じだね。
大体、「デストラクタ」と言っているのだから
POD型ではないので、「(大抵の処理系で)実行開始時に確保されてる」等の
Cの話は関係ない。
むしろ、こういうものだと捉えない
>>832 >>846 が不思議。
あ、デストラクタの呼び出し順は、生成と逆順であることが保証されているよ。
実装的には、初期化時はフラグ(大抵排他制御されてない)を使って判定して
内部的にatexitのようなもの登録することで
デストラクタを呼び出しているものが多いみたいね。
>>850 > デストラクタの呼び出し順は、生成と逆順であることが保証されているよ
関数内のstaticオブジェクトも?
MAJIDE?
>>847-850 すまん、確かにお前等の言うとおりだった...。
全然勘違いしてた。orz
>>831 > 破棄のタイミングはmain関数より後なんで。
そもそも、main 関数終了後まで生き続けるスレッドなんて言うものを
言語仕様策定時に想定していなかったか、想定しててもそれはプログ
ラマ側の責任だよと言うことなんだろうな。
>>851 > 関数内のstaticオブジェクトも?
> MAJIDE?
マジみたい、
VC++ 2005 でやってみると、コンストラクタを実行する時にデストラクタを
登録している。
>>850 の言う通り初回かどうかの判定は排他制御されてないフラグでやって
るからマルチスレッドだと注意しないとえらいことになりそう。
ここ30年前ほど悩んでいるのだけれど、静的変数の初期化ってどうやって排他する のでしょうか? void f() { static class X i; // ←初期化が排他制御されない。 } これを回避するために void f() { X* px; static Mutex mutex; { MutexLock lock(mutex); static class X i; px = &i; } px->zzz(); } としたのですが、mutexの初期化が排他制御できないのです。 mutexをメインスレッドに置くぐらいしか思いつきませぬ。
mutexを関数の外に出せば、main実行前にメインスレッドで初期化されるね
C互換構造体を使う(BinaryHacksより) って方法はダメ?
>>855 static initialization order fiascoが問題になる
一般的には、lockを関数の外に出して、コンストラクタで初期化するべき。 何か事情があって、どうしても関数内で行う必要があるとき(例えばDLL内など)は CASを使ってlockへのポインタを初期化することで、なんとかなる。 オブジェクトが複数確保しても(余剰分はすぐ解放する)コスト等で問題ないなら オブジェクト自体をCASを使って確保する手もある。
マルチスレッドには関係ないがVBのStaticには何度もだまされた記憶がある
>>858 CASってあんまり知らないけど、マシン語レベルでメモリに書き出したつもりでも
片方のスレッドだけCPUキャッシュでライトバックされて矛盾とか起きないの?
ちなみにWindowsだったら名前付きイベントで同期が可能かなと思った。
>>860 矛盾が起きないようにするためのキャッシュアルゴリズムなのである。
>>854 > ここ30年前ほど悩んでいるのだけれど、
C++ が開発されてまだ 25年しか経ってないんだけど、未来からお越しの方ですか? (w
>>861 >
>>855 > そいつは処理系依存
「mutexを関数の外に出せば、main実行前にメインスレッドで初期化されるね」とならない
処理系なんてどうやって作るんだ?
#
>>854 が「mutexをメインスレッドに置くぐらいしか思いつきませぬ。」って書いてるか
# ら、
>>855 の書き込みはあまり意味がないというなら分かるが。
rw_lockの実装ってどっかにのってないですか?
後出しジャンケンって嫌われるよね
>>860 例えばWindowsなら、InterlockedCompareExchange()を調べてみ
869 :
デフォルトの名無しさん :2008/06/22(日) 21:46:05
Java Docを見たのですが、ThreadLocalが何のために使うのかわかりません。 どこかわかりやすく説明しているサイトはないでしょうか?
用途のわからないものをわざわざ使おうとする必要はないような・・・
まあそんなことを言うと進歩がないわけで、興味を持つのは 悪くないと思うよ。 ただ、ThreadLocal は Thead でいろいろやらないと必要性が ちょっと分かりにくいものだから、Thread で色々遊んでから 調べた方がいいかも知れない。 機能としては、Java Doc に書いてある通りだし。
>>869 セキュリティとかトランザクションとかスレッドに結びつけた情報を覚えておくため
>>869 じゃないけど俺もTLSの使い道がわからない。
特にJavaみたいなガベージコレクションのある言語なら
Runnableクラスに変数1個定義するだけで十分に思えてしまう。
あれ、errnoは普通は関数呼び出しに置き換わるんだっけ? まあ、それでも内部的にはその呼び出し内で使われてるでしょ。普通は。
ていうか__threadって、Win32に限らんな。 sunやhpのマニュアルもヒットするし gccも3.3以降なら__threadで使えるのか。
877 :
デフォルトの名無しさん :2008/06/23(月) 07:26:35
Javaで別のスレッドで作られたオブジェクトに対してメソッド呼び出しすると、 どっちのスレッドで動くの? 混ざり合わないの? class Hoge implements Thread{ private Object o; // Hogeスレッドのもの? public static void main(String[] args){ new Thread(new Hoge()).start(); new Thread(new Piyo()).start(); } public Hoge(){ Thread.currentThread().setDaemon(true); } public void run(){ setValue("aa"); } public void setValue(Object v){ o = v; } // Piyoスレッドから呼ばれたときはスレッド固有の値同士が混ざり合わないの?TLSじゃないの? } class Piyo implements Thread{ public Piyo(){ Thread.currentThread().setDaemon(true); } public void run(){ setValue("bb"); } }
根本的にわかってないでしょ。 もうちょっと書籍とか呼んでがんばって濃い。
まぁヒープ領域に確保されたオブジェクトはスレッドと関連付けられてるのかって聞きたかっただけなんだけどな
javaもアノテーションでTLSできたら楽なのにね。 @threadlocal static int hoge = 0; みたいな感じで。
え?じゃあどういう話だったの?
javaのThreadLocalは、staticなメソッドで必要なオブジェクトを毎回作りたくないときに使う。 もちろんそのオブジェクトがスレッドセーフならかまわないけど。
>>882 スレッドとかいう話じゃなくて、インスタンス変数の概念が無かった
という話。だから
> private Object o; // Hogeスレッドのもの?
こういう疑問が生まれる。
> public Hoge(){ Thread.currentThread().setDaemon(true); }
これはひどい・・・
ThreadLocalと言うと >Runnableクラスに変数1個定義 出来ない場合にも使うよな。 フレームワークでThreadを管理している場合とか。
>>884 いやインスタンス変数というか,インスタンスとかクラスベースオブジェクト指向言語の話題は十二分に分かってると自負してるんだが
JavaのスレッドがWinAPIのスレッドと結構毛色が違うので混乱していた
まだちょっと分からないんだけど,Javaのオブジェクトってスレッドに関連付けられて作られるわけじゃないの?
ただのヒープ領域に割り当てられるだけなの?
> > public Hoge(){ Thread.currentThread().setDaemon(true); }
> これはひどい・・・
run()に書くべきだった・・・
ヒープが自動的にスレッドローカルになるの>WinAPI
Javaのスレッドはどうなってるのか聞いてみた
>Javaのオブジェクトってスレッドに関連付けられて作られるわけじゃないの?
>ただのヒープ領域に割り当てられるだけなの?
Yes。スレッドとは縁もゆかりもない。スレッド固有でもなければスレッドごとに
値が異なるわけでもない。ただnewした数だけインスタンスが存在する。
>>887 イミフメ
ドトネトのForms連中が、ThreadAffinityのある全メソッド・プロパティで 保存しておいた作成時ThreadIDと、実行中のThreadIDを チェックして例外発生させてたけど、そんな感じが自動実装されるってか?
>>889 はあく
これで安心してJavaプログラミングできるわ
892 :
デフォルトの名無しさん :2008/06/23(月) 22:05:50
初カキコです。 C++です。beginthreadexで作ったスレッドを処理途中で強制的にリセット (処理開始前の状態)できるきるような便利な機能ってありますか? なければどなたか実装方法アドバイス頂けないでしょうか? アセンブラとかいじればできるのかな〜?
パンプティダンプティ割れてしまった卵は・・・ Transactinal Memoryで何とかなるのだろうか
スレッド関係ねぇな
>>892 イベントなりフラグなり立てて処理をキャンセル汁
r ‐、 | ○ | r‐‐、 _,;ト - イ、 ∧l☆│∧ 良い子の諸君! (⌒` ⌒ヽ /,、,,ト.-イ/,、 l |ヽ ~~⌒γ⌒) r'⌒ `!´ `⌒) 人生にリセットボタンは無いが │ ヽー―'^ー-' ( ⌒γ⌒~~ /| 電源ボタンはあるんだ! │ 〉 |│ |`ー^ー― r' | │ /───| | |/ | l ト、 | めんどくさくなったら押してみるのも一興だな。 | irー-、 ー ,} | / i | / `X´ ヽ / 入 |
>>892 できないし、実装しようとするのも勧められない
共有変数 A = 0として
スレッド1がAをインクリメント
スレッド2がAをインクリメント
スレッド1リセット
Aの値は?
>>897 あおりはスルーでおねがいします
>アセンブラとかいじればできるのかな〜?
アセンブラに夢持ちすぎ とりあえず素直にユーザが実装すべき
普通に実装すりゃ簡単に実現できるが、めんどくせぇとかほざいてんのか? 「スレッドを初期状態に戻す」とか 「リセットしたくなったら」とか 定義が曖昧でよくわからんが スタック変数にリソース管理させてリセットしたくなったら例外でも投げとけ。 そんなコードを仕事で見かけたら糞味噌にするが趣味コードなら誰も文句いわねーよ
なんとここで釣れた釣れた宣言が・・・!!
あるスレッドでHDDを初期化しまんた スレッドをリセットしたので初期化したHDDが元に戻りまんた こんなのにも万能に対応しろってことかい?
なんという参照透過性による副作用の排除
タイムマシン型スレッドを作って、スレッド消したら時間が戻る…
データベースのロールバックみたいなもんかな
PCIバスに差すやつで、リセットなり電源オフなりすると HDDの内容元に戻るのがあったな。
ループしてしまう
なにそのデジタル版三途の川
>>848 > しないよ。それは規格(ISO/IEC 9899:1999, ISO/IEC 14882:2003)で決まってる。
どうしてそんな嘘つくかなぁ…
ISO/IEC 9899:1999は隅々まで読んだが、そんなこと書いてないぞ。
規格中はこれだから(ry
C++の規格の関係ありそうなところだけ読んでみたが、
>>837 はPOD型だから
関数に入る前から初期化することが許されているな。
>>848 の場合は「その宣言に初めて制御が渡った時点で行われる」と書いてある。
でもCだと確かローカルなstaticは定数でしか初期化ができなくてそれもmainの実行前だよな。
C99の6.2.4と6.7.8確認したが、定数式による初期化のみで、プログラム 実行前に初期化だな。 確かに「関数内で作った」と言われるとすごい違和感ある。
読み込み専用ロックしてる最中に 別スレッドで書き込みが発生すると、データが強制的に書き換わるのですが どうやって防止すればいいのですか?
加齢にスルー
>>914 それは俺の国の言葉では「ロックできてない」と言う。
>>914 書き込みロックを取得せずに書き込む奴が悪い
先に読んでおいてスタックにでも置いとけ。
>どうやって防止すればいいのですか? バグを治す
mutexでロックしてるのに書き換わるよなんで?
mutexをロックしただけなら、そのmutexを見ないやつには関係ないべ。
mutexは他のデータをロックをしない。mutexデータだけがロックされる。 mutexと他のデーターの関連は自分でプログラムする。
ロックしたのにロックされてねえ、 こりゃロックだ
そんな症状が断言できるほど長時間のロックをする設計は間違っている。
_beginthreadex()関数の第6引数が引っかかってなぜかコンパイルが通りません。 「'unsigned long' から 'void *' に変換することはできません。」と出ます。 DWORD ThreadID; _beginthreadex(NULL, 0, (unsigned int (__stdcall *)(void *))MainThreadProc, NULL, CREATE_SUSPENDED, (unsigned int *)&ThreadID); ……と書いてるのですが、何が問題なのでしょうか? 環境はWindows2000, Visual C++ 6.0 SP5 process.hインクルード, [コード生成]→使用するランタイムライブラリ→マルチスレッドに指定しています。
ちなみに、(unsigned int *)&ThreadID ……の部分をNULLにしても同様のエラーが出ます。
まず、MainThreadProcがキャスト無しで渡せなければ話にならないのだけれど、 例えば__stdcallで良いのか、とか。
VC9でそのコード丸ごとコピペしたら通ったけどな…。 ほんとにエラーそれだけ?
>>930 3番目の引数をキャストなしで書くと以下のエラーがでます。
『3 番目の引数を 'unsigned long (void *)' から 'unsigned int (__stdcall *)(void *)' に変換できません。』
>>931 >>928 のコードではエラーはこれ一つだけです。
>>932 そこはキャストを使うべきではない。関数の宣言が違ってないか?
よく見たらスレッド関数が DWORD WINAPI MainThreadProc(LPVOID Param){〜略〜}; ……になってました。 unsigned __stdcall MainThreadProc(void * Param){〜略〜}; に変更すると第3引数はキャストなしでもいけました。 しかし、第6引数を起因とするエラーは変わらずでます。 ちょっと落ちます。
とりあえず、別にテスト用のプロジェクト作って 最小限のコードで問題が再現されるか試してみたらどうかな。
pthreadで各スレッドローカル変数ってアクセス遅い?
pthreadをなんだと思っているのだろう……
スレッド作るやつ?
名前の通りスレッドのポインタ
>>928 ですが、解決しました。
結果からいいますと、_beginthreadex()の返り値を"(HANDLE)"でキャストすることでコンパイルがとおりました。
HANDLE hThread=NULL;
DWORD ThreadID;
hThread=(HANDLE)_beginthreadex(NULL, 0, MainThreadProc, NULL, CREATE_SUSPENDED, (unsigned int *)&ThreadID);
なんともお騒がせしました。
ちなみにスレッド識別子ですが、宣言としてはCreateThreadの場合のように
DWORD ThreadID……でいいのでしょうか?
それともmsdnのサンプルのように、
unsigned ThreadID……の方がいいのでしょうか?
前者のように明示的に宣言する方が分かりやすくていいのですが、
後者だと第6引数をキャストする必要がなく簡潔に書けるので―――どうなんでしょう。
CreateThreadが返すスレッド識別子と同じ物だろうし どっちの型も(たぶん)32ビットだから、 キャストによる値の変化はないだろうという前提で…… 一般的にはキャストしない記述が望ましいが、 理解して意図的にキャストするなら別に文句は言わない。 あとでThreadIDを使うときにみっともないキャストを連発するぐらいなら 最初からDWORD ThreadID;で定義したほうがマシかもね。
>>DWORD ThreadID……でいいのでしょうか? お前の使用している開発環境のヘルプにunsignedと書いてあるんだろ? DWORDと書く理由が思いつかないのだが。仕様をみてプログラム書け。
>>941 サンプルだけじゃなくWin32APIリファレンスやヘッダをよく読むのだ。
longとintは“区別”しとけよボクぅ?
>一般的にはキャストしない記述が望ましいが、 これはこの通りなんだが、戻り値はキャスト必須な時点でどうでもいいわなw 実質CreateThreadなんでCreateThreadと同じ変数を用意しておくのが無難ってもんだ。 てかこの程度でつまづくようなら大人しくboost他のラッパークラス使っておいた方がマシな気がしないでもない。
longとintってなにが違うの? 両方とも32ビットの整数でしょ? 64ビット環境でもあるまいし。
ここにも危険思想の持ち主がひとり…
>>947 Unix界隈だと long 64bbit, int 32bit だったりするんだな
64ビット環境でも LLP64 ならlongは32bitだけど・・・
環境によってはintは16bitだな
longって略さずにlong intって書こうぜ?
だったらsignedもつけようぜ
もちろんdouble floatもだよな?
>>955 SPARC/SolarisとかLP64(longとポインタが64bit)って呼ばれる環境がある。
旧DECのAlpha/Digital UNIXのようにILP64(int、long、ポインタが64bit)もある。
Win64のポインタが64bitでint、longが32bitってのは変態すぐる。
>>955 Linuxだと long のサイズとポインタのサイズが同じという前提でプログラムが
書かれてることが結構ある(カーネルの時点ですでにそうだし)
64bit環境で普通にコンパイルすれば long が64ビットになる
x64は64bitレジスタをいじる命令が32bitレジスタをいじる命令より1バイト長い という食わせ物だから。intまで64bitにしたくないのはわかる。
Win16のときのlong=32bitのまま引きずってるから、longを64bitに できなかったんだろうな。 Win32ではintでいいところでlongを多用してるし。 まぁ、16bit時代から互換性を重視しながら続いているのが原因で、 しょうがないとは思う。生まれたときから32bitのOSとは事情が違うでしょ。 どうせtypedefされた型名しか使わないから、どこかの時点でlongを 使っている部分をintに変えてもよかった気はするけどね。
long long どっかの南の島の爺さんが語る昔話の話し出しみたいな ろぉんぐ、ろぉんぐ、あるところに・・
API自体が使うのはLONGとかDWORDとかINT_PTRとかなんだから、 別にCのlongが64bitだろうが行けなくはないはずなんだがなー
Linux(笑)
964 :
955 :2008/07/02(水) 07:26:01
>>956 32ビット環境でlongが64ビットの例が欲しかったのだが・・・。JavaとかC#みたいな。
>>957 Alphaは大昔に使ったけどintは32では?
初心者ですが、32bit Windows環境だと 単なる "unsigned宣言" は "unsigned long宣言" と同義ということですか?
言語的には unsigned は unsigned int と同義。 で long がたまたま int と同じ長さだと、そうなる。
SGIのにILP64なのがあったはず。AlphaはLP64でしょ。
同義じゃないだろ。 unsigned i1; unsigned long i2; std::printf("%s\n", typeid(i1).name()); std::printf("%s\n", typeid(i2).name()); i1とi2は「サイズが同じ」だけで同義じゃない。 あと『単なる "unsigned宣言"』という前提から少し外れるが、ポインタの互換性はない。 typedef unsigned long t1; typedef unsigned t2; t2 *p = (t1 *)0; // compile error
同じ働きをすると言ってるだけで、誰も同じ型だとは言ってないよ。
整数の型を省略したらsigned, intが勝手に着くとかあったなぁ
main(c, char **s){ }
最近は省略してもintと解釈しなくなったんじゃなかったっけ
974 :
969 :2008/07/03(木) 07:28:22
>>970 その「同じ働き」ってのが曖昧じゃないか。typeid比較する
コードがあったら違う挙動になるのは同じ働きとはいえないだろ。
サイズが同じだけで別の型だって念を押しておかないと
>>965 は
unsignedとunsigned longの入り交じったソース量産するぞ。
975 :
デフォルトの名無しさん :2008/07/03(木) 07:46:53
posixのスレッドローカルデータって 上限値って決まってるのでしょうか
データの個数?総サイズ?
サイズなら上限は当然あるだろ 数値は実装に依存するが
>>974 int a;
int b;
a と b のアドレスを比較するコードがあったら違う挙動になるんですが、
a と b は違う働きをするんですか?
>>977 スタックサイズが64kbか128kbなので
個別スレッドで4Mのデータを扱えません
>>980 なんで全てのデータをスタックに入れようとするんだよ。
>>979 違うとえば違うような。変数と型を一緒にしてない?
>>980 回避方法はあるけど、TLSを使わない方針で設計を見直すべき。
>>984 じゃあ使わないからどうやればいいのか教えてください
スレッドごとにメモリを動的確保すればよい。メモリの解放には注意して。
>>985 使わなくてもいい方法を一度考えてから質問しようぜ
>>987 mutexしたくないので使わないと無理です
まさか、グローバル変数だけで作ってるのか?
うん
>>990 NT系列のコーディング規約でそうなってるの
どうすればいいの?
グローバル変数の使用が強制されたコーディング規則だと・・・ もちろん釣りだよな。
今人気急上昇中の組み込み系かもしれない
>>992 いやまじなんですよ本当に
コーディングルールの
項4.5.1に、共有データはグローバル変数として
定義し他者が利用しやすいように記述すること
って載ってるんですよ
本当に助けてくださいまじで困ってます。
もう吊ろうかな3日も寝てなくて頭おかしくなってきたし
>>994 TLSにデータを置いたら、他のスレッドからアクセスできなくなるから共有にならないけどいいの?
>994 共有データって書いてあるじゃん。 共有データじゃないものには適用するな。
>>994 今やってるところは個別のスレッドで
データ作って処理するところなんですよ
規約でグローバル変数は共有する場合だけ
だから使うなって言われたけどどうすればいいか
わからないし
>>997 使うなっていわれたんだから使わないでOK
グローバル変数は使わないのが正道
>>997 個別のスレッドでデータ造って処理するんだから、他のスレッドと
共有なんかしなくていいんだろ。
だから、グローバルを使わなくていいんだし、素直に
>>986 でい
いだろ。
スレッドローカルデータがどうのこうのの前に、日本語理解力と
コミュニケーション能力を何とかした方がいいと思うよ。
時間切れとなりました
1001 :
1001 :
Over 1000 Thread このスレッドは1000を超えました。 もう書けないので、新しいスレッドを立ててくださいです。。。