- 1 名前:名無しさん@お腹いっぱい。 mailto:sage [2006/12/20(水) 22:11:47 ]
- Posixな糸に群がる亡者どものスレ。地獄の底でsage進行。
徳の高い人はpthread天国でも可。 ■前スレ pthread地獄 pc8.2ch.net/test/read.cgi/unix/1010933537/
- 106 名前:93 mailto:sage [2008/07/22(火) 18:20:41 ]
- >>105
どういうレベルかと言われると良く判らないのですが、 SIGSEGVとか、SIGILLとか、SIGFPEとかのシグナルは、同期シグナルと呼ばれていて、 スレッド側で、signal(3)でハンドラを設定しておいてあげれば、そのシグナルを発生させた スレッドがシグナルを受け取ってくれるみたいです。 "pthread 同期シグナル" でぐぐった時の2ページ目の最後のマルチスレッドのプログラミング というSunのPDFへのリンク先の資料に書いてありました。 Solaris10(x86)と、FreeBSD(i386)でサンプルを作ってみたところ、スレッド側で定義した シグナルハンドラでpthread_self()すると、ちゃんとしたスレッドIDが取得できました。
- 107 名前:93 mailto:sage [2008/07/22(火) 18:55:40 ]
- ちゃんとしたスレッドIDってのは、SIGSEGVを発生させたスレッドIDって言う意味です。
- 108 名前:105 mailto:sage [2008/07/22(火) 20:40:51 ]
- >>106
ありがとうございます。 comp.programming.threads FAQにも、 Q40: Which signals are synchronous, and whicn are are asynchronous? というのがあって、同じような記述がされてました。 POSIXとかの仕様として挙動がちゃんと決まっているなら、安心してこの性質が使える と思うのですが、実装依存と言われると便利だけど使いにくいなぁと思ったもので…
- 109 名前:名無しさん@お腹いっぱい。 mailto:sage [2008/07/23(水) 09:00:47 ]
- 使うべきなのは条件変数じゃなくてセマフォ。
子スレッドは終了時にsemaphoreを解放して、 管理スレッドはsemaphoreを得てスレッド作ればいいだけの話。 シグナルハンドラから安全にpthread_*呼び出せるかどうかは知らんがな。 やろうとも思わん。
- 110 名前:名無しさん@お腹いっぱい。 mailto:sage [2008/07/24(木) 00:03:24 ]
- 条件変数とmutexがあればセマフォも実装できるから同じことだよ。
mutex で保護したカウンタを、スレッド数で初期化して作っておいて、 待つ側のスレッドはそのカウンタが0になるまでpthread_cond_wait()、 終了するスレッドは、pthread_exit()する直前にカウンタをデクリメント、 もしカウンタがゼロになったらpthread_cond_signal()すればいいだけ。 かんたん。 pthread_join()は使う必要ない。 あとSIGSEGVが起きているということは、そのプロセス内のメモリ空間は ぶち壊れて不整合が起きているってことだから、さっさとプロセスごと 死ぬべき。そんな状態で動作を続けたら、誤動作して余計悲惨なことに なるのがオチ。
- 111 名前:名無しさん@お腹いっぱい。 mailto:sage [2008/07/24(木) 01:25:25 ]
- まあ、世の中にはsigaltstack(2)というものもあるわけでね。
SEGVから戻ってこれるケースもあるわけで、そこまで言いきるのはどうかな。
- 112 名前:名無しさん@お腹いっぱい。 mailto:sage [2008/07/24(木) 02:29:58 ]
- 確かにそういうケースもあるにはあるな。
>>98は明らかにそういうケースじゃないけどな。
- 113 名前:93 mailto:sage [2008/07/24(木) 09:46:56 ]
- 複数のワーカースレッドの終了を待つロジックを書いてみた。
/* 全てのワーカースレッドの終了を待つ */ pthread_mutex_lock(&m_end); while (0 != thread_num) { while(NULL == thr_end) { pthread_cond_wait(&c_end, &m_end); } nrc = pthread_join(thr_end, NULL); if (0 == nrc) { fprintf(stdout, "thread %5d is exited...\n", thr_end); --thread_num; thr_end = NULL; }else{ fprintf(stdout, "Error pthread_join() return %d\n", nrc); } pthread_cond_broadcast(&c_end); } pthread_mutex_unlock(&m_end); fprintf(stdout, "ALL thread is exited... thread_num=%d\n", thread_num);
- 114 名前:93 mailto:sage [2008/07/24(木) 09:47:40 ]
- こっちがワーカースレッド側
/* メインスレッドに処理終了を通知 */ pthread_mutex_lock(&m_end); while (NULL != thr_end) { pthread_cond_wait(&c_end, &m_end); } thr_end = pthread_self(); pthread_cond_broadcast(&c_end); pthread_mutex_unlock(&m_end); pthread_exit((void *)NULL);
- 115 名前:93 mailto:sage [2008/07/24(木) 09:51:36 ]
- やっと、条件変数の使い方が判った。
添削してもらおうとは思ってないけど、とりあえずいろいろ教えてもらったので 張っときます。 複数の子プロセスの任意のタイミングでの終了を親プロセスが待つって いうケース(親がwaitpid(2)で任意の子プロセスの終了を待つ)を想定してます。
- 116 名前:名無しさん@お腹いっぱい。 mailto:sage [2008/07/24(木) 10:44:00 ]
- 子が正しく死ぬなら、semaphoreでやるのが楽そうではある。
- 117 名前:93 mailto:sage [2008/07/24(木) 11:24:46 ]
- セマフォでやるってのがいまいちピンと来ないんだけど。
親(メイン)スレッドがいつ居なくなるか判らない複数の子(ワーカー)スレッドの終了を待っていて どれかの子(ワーカー)が居なくなったら、それをハンドリング(どの子が居なくなったかを認識)するってどうやるの?
- 118 名前:名無しさん@お腹いっぱい。 mailto:sage [2008/07/24(木) 11:37:20 ]
- わかりにくいし余計なスレッド起床も伴うから
条件変数は使いまわさず親スレッド起床用と子スレッド起床用とで分けた方がよくね?
- 119 名前:名無しさん@お腹いっぱい。 mailto:sage [2008/07/24(木) 11:46:43 ]
- 勘違いしてた。単純に死んだのを取りこぼさずに知りたいわけではないのか。
じゃあやっぱcondかな。
- 120 名前:名無しさん@お腹いっぱい。 mailto:sage [2008/07/24(木) 12:01:12 ]
- 作ってdetachして放置。
子から親になにか渡さないといけないなら、親側に渡してから死ぬ。
- 121 名前:名無しさん@お腹いっぱい。 mailto:sage [2008/07/24(木) 12:04:34 ]
- 子スレッドの数だけ充足するならsemaphore、
ハンドリングまでするならqueueだな。 どちらもmutexとcondition variableで書けるのはいいとして、 pthreadでの標準的な実装はないのかな?
- 122 名前:93 mailto:sage [2008/07/24(木) 12:52:22 ]
- >>118
最初はそう考えたんですが、親がcond_waitしてないときに子が親にcond_signal するケースを考えると、なんか余計に複雑になるような気がして、 >>113 >>114 に落ち着いたんです。 条件変数分けると、mutexも分けないといけないし。 (ん? 条件変数だけ分けてmutexは使い回せばよい?) もっかい考えてみる。 >>120 ケースバイケースだと思うんだけど、pthreadでプログラム作るときって、detachするのが どっちかと言うとデフォなの? >>121 そうなんですよね。 こんなのって定石だと思うんですが、なんでpthread_XXが無いんだろう?
- 123 名前:93 mailto:sage [2008/07/24(木) 13:11:48 ]
- >>121
>ハンドリングまでするならqueueだな。 あー、確かに、queue作って、子が死ぬ前に突っ込んで親がそれを拾えば うまくいきますね。 子が居なくなるのと親がそれを検出するのの同期を取らなくても良い場合は、 それが一番良さそうな気がしますね。
- 124 名前:名無しさん@お腹いっぱい。 [2008/07/24(木) 13:38:01 ]
- >>121
セマフォは普通にPOSIXのセマフォ使えばいいよね
- 125 名前:93 mailto:sage [2008/07/24(木) 13:50:31 ]
- >>118
こんな感じですか。 ワーカー側でcond_broadcast使わなくても良くなったので、無駄なスレッドが 起こされなくなってちょっと軽くなったのかな。 ボス側 pthread_mutex_lock(&m_end); while (0 != thread_num) { while(NULL == thr_end) { pthread_cond_wait(&c_end_boss, &m_end); } nrc = pthread_join(thr_end, NULL); if (0 == nrc) { fprintf(stdout, "thread %5d is exited...\n", thr_end); --thread_num; thr_end = NULL; }else{ fprintf(stdout, "Error pthread_join() return %d\n", nrc); } pthread_cond_broadcast(&c_end_work); } pthread_mutex_unlock(&m_end); ワーカー側 pthread_mutex_lock(&m_end); while (NULL != thr_end) { pthread_cond_wait(&c_end_work, &m_end); } thr_end = pthread_self(); pthread_cond_signal(&c_end_boss); pthread_mutex_unlock(&m_end); pthread_exit((void *)NULL);
- 126 名前:93 mailto:sage [2008/07/24(木) 19:31:08 ]
- pthreadとシグナルについてですが、
同期シグナルは発生要因となったスレッドに送られ、そのスレッド上でシグナルハンドラが起動される。 非同期シグナルは、それを受け取る準備をしているスレッドに送られる。(結果的に、同期的にシグナルを扱うことが出来る) いずれの場合も、シグナルを受け取ったスレッドでpthread_XXを使ってもうまく動くと思うんですが、間違ってますか? ようは、SIGSEGVのハンドラからpthread_XXを呼んでみるとうまく動いているように見えるんだけど、 これって、実装(環境)依存なだけなのか、そうでないのかが知りたいんです。
- 127 名前:名無しさん@お腹いっぱい。 mailto:sage [2008/07/25(金) 02:27:24 ]
- 実装依存以前どころか、たんに運がいいだけである可能性が高いな。
SIGSEGVが起きる状況の場合、SIGSEGVのきっかけとなったメモリ破壊の結果、 pthread_mutex_tやpthread_cond_tまで巻きぞえをくらって壊れている可能性 がある。その状況でpthread関数を呼んでちゃんと動く保証なんてありえない。 シグナルハンドラから呼ばれて正常動作する保証があるのは、マニュアルに async-signal-safeと明記されている関数だけ。 そういう関数は、実際のところはシステムコールであることが多い。
- 128 名前:93 mailto:sage [2008/07/25(金) 10:14:40 ]
- 確かにそういうケースだとpthread関数がまともに動く可能性はないかもしれないですね。
私がSIGSEGVを発生させたパターンは単に、NULLアドレスに書き込んでるだけなので、 その辺のデータ(pthread関数が使用している内部データ)を壊してるって訳ではないです。 そもそも、シグナルハンドラからPthread関数が呼べない理由ってのは何故なんでしょう? Pthread関数の内部データはそのスレッドのスタック上に存在していて、 シグナルハンドラはスレッドとは別のスタックを使って実行されるからって事ですか?
- 129 名前:名無しさん@お腹いっぱい。 mailto:sage [2008/07/25(金) 11:07:22 ]
- 仮にシグナルハンドラからpthread_*が完全に問題なく呼べたとしても、
mutexとかのリソース持ってる状態でシグナル発生したら状態復旧は絶望的だお。
- 130 名前:名無しさん@お腹いっぱい。 mailto:sage [2008/07/25(金) 11:13:24 ]
- おれもわざわざそんな茨の道に行かなくてもと思う。
- 131 名前:名無しさん@お腹いっぱい。 mailto:sage [2008/07/25(金) 11:44:36 ]
- そこまで苦労してまでバグを直接修正したくない理由の方に興味がわいてきた。
- 132 名前:93 mailto:sage [2008/07/25(金) 12:44:25 ]
- 今、気になっているのは、Webサーバの様なサーバプログラムで、ボスは常にaccept()待ち。
クライアントからの接続があったら、ワーカーを起動して、そのあとの処理はワーカに任せる。 といった、定番的なネットワークサーバを書く場合に、いわゆるfork()モデルと、スレッドモデルで どのような差があるのか(特にエラー発生時において)という事です。 なので、ワーカー側の処理ってのは、基本的に独立していてワーカー同士で共有を行うデータも 不要であると考えています。 非同期シグナルも使う必要は無いと考えています。(多分) fork()モデルの場合は、ワーカプロセスが同期シグナル(SIGSEGV,SIGILL等)を発生させたとしても、 他のワーカープロセスへの影響は特に無く、再度クライアントが接続してくれば、また、サービスを 再開することが出来ます。 スレッドモデルで同じことを実装することは可能なのか? 特定のワーカーが何らかの理由で同期シグナルを発生させた場合、その特定のワーカが死ぬのは しょうがないと思うんですが、他のワーカーまで道連れにしてしまうのは避けたいと思っています。 スレッドモデルを使ってこのような処理を安全に書けないって事は無いんじゃないのって思うんですが、 いかがなもんでしょう? また、MySQLはマルチスレッドで動いているらしいのですが、こういったDBサーバは更に複数のワーカ間で データの排他や同期を取る必要があると思うんですが、こういったプログラムは同期シグナルとどうやって 折り合いをつけているんでしょうか。 これがいわゆる茨の道ってやつですか?
- 133 名前:93 mailto:sage [2008/07/25(金) 12:52:01 ]
- >>131
まだ、なにも作ってないですよ。 pthreadというか、マルチスレッドのプログラムを作るのが始めてなので、 いろいろサンプルを作って勉強している最中です。 このスレとっても勉強になります。 レスしてくださっている皆さんありがと。 ところで、本屋行っても、pthread(マルチスレッド)に関する書籍ってほとんどないですよね。 あっても、10年ぐらい前に出版されたものが殆んどで。 この先、CPUはメニィコアに進もうとしているからもっと沢山あっても良いと思うんですが、 pthreadってあんまり使わないんですかね?
- 134 名前:名無しさん@お腹いっぱい。 mailto:sage [2008/07/25(金) 12:57:45 ]
- > スレッドモデルで同じことを実装することは可能なのか?
想定しているのがSIGSEGVやSIGILLのようなプログラムロジックの バグである限り、不可能というのが答。 プロセスには、スレッドに比べて、メモリ空間が分離されていて SIGSEGVやSIGILLのような誤動作の影響を完全に排除できるという 特徴がある。つまり、まさにプロセスの利点に当てはまるケースな わけで、このような想定状況で、スレッドにプロセスと同等の信頼性 を求めることはできない。 > こういったプログラムは同期シグナルとどうやって折り合いをつけて > いるんでしょうか。 バグが原因で発生するシグナルは別として、sigwait() で対処するのが常識。
- 135 名前:93 mailto:sage [2008/07/25(金) 13:40:09 ]
- >>134
そっか。 やっぱりそうなんですか。 非同期シグナルであれば、シグナル受け専のスレッドを立てておいて、そこで sigwait()するってのは判るんですが、同期シグナルはsigwait()では待てないですもんね? ん?待てるのか? ちょっと試してみる。 でも、待てたとしても、どのスレッドがその同期シグナルを発生させたかって、シグナル受け専 スレッドで判らないけりゃどうしようもないですし。
- 136 名前:名無しさん@お腹いっぱい。 mailto:sage [2008/07/26(土) 12:58:41 ]
- 悪いこといわねえだ。signal扱いたいならprocess村に帰った方がええ。
- 137 名前:名無しさん@お腹いっぱい。 mailto:sage [2008/07/26(土) 17:23:08 ]
- つ libevent
- 138 名前:名無しさん@お腹いっぱい。 mailto:sage [2008/07/26(土) 19:24:07 ]
- libevent はマルチスレッド環境でも安全に使う方法があるってだけで、
それ自体がスレッドセーフな作りになってるってわけじゃなかったはず。
- 139 名前:93 mailto:sage [2008/07/29(火) 10:32:25 ]
- とりあえず、やってみました。(Solaris10 x86です。)
ボス側で全てのシグナルをブロックし、シグナル受信専用スレッドを作成し、そこでsigwait()。 ワーカースレッドでSGISEGVを発生させるために、NULLアドレスに書き込み。 結果は、プロセスごと終了。 同期シグナルは発生元のスレッドに送られるのでシグナル受信専用スレッドでsigwait()していても 捕まえる事が出来ないってことですね。 同期シグナルは、ワーカースレッド側でsigset()して、シグナルハンドラ側でボスに >>125 すれば、 とりあえずハンドリングは出来ますが、 >>127 にもあるように、どこまで動くのかは不明ですね。 >>134 にもあるように、この辺りがマルチスレッドと、マルチプロセスの差という事なんですね。 そもそもスレッドってなに?、スタックとスレッドの関係って?、プロセスとスレッドの関係って? OSはスレッドをどう認識してるの? なんてことが判っている人にとっては自明なんでしょうが、私にもようやくこの辺りが判って来た 様な気がします。 なかなか使いどころが難しいですが、面白い仕組みですね。
- 140 名前:名無しさん@お腹いっぱい。 mailto:sage [2008/07/30(水) 21:16:41 ]
- シグナルのことを考えるとunixでスレッドをモリモリ使うのはキツい。角度とか。
- 141 名前:名無しさん@お腹いっぱい。 mailto:sage [2008/08/09(土) 19:15:44 ]
- あと、子プロセス生成(fork)も相性が悪くて、深い悲しみに包まれた。
- 142 名前:名無しさん@お腹いっぱい。 mailto:sage [2008/08/09(土) 20:02:32 ]
- マルチスレッドプログラミング→排他漏れ続出→永遠とバグが取れない→いくえ不明
- 143 名前:名無しさん@お腹いっぱい。 [2008/08/09(土) 20:41:21 ]
- 俺はマルチプロセスを使い手なんだが相手が残念な事にスレッドを使ってきたので「お前それで良いのか?」と言うと「何いきなり話かけて来てるわけ?」と言われた。
俺の弟がスレッドの熟練者なのだがおれはいつも勝つから相手が気の毒になったので聞いただけなんだがむかついたので「お前シグナルでボコるわ・・」と 言ってmain直後に力を溜めてkillしたら多分リアルでビビったんだろうな、、pthread_sigmaskしてたからサスペンドしてカカッっとforkしながらkillしたらかなり青ざめてた おれは一気にlongjmpしたんだけどスレッドが硬直してておれの動きを見失ったのか動いてなかったからコマンド投下で排他を崩した上についげきのデッドロックでさらにダメージは加速した。 わざとセマフォをとり「俺はこのままタイムアウトでもいいんだが?」というとようやく必死な顔してなんかコードのはしっこからブロック型システムコール出してきた。 おれはselectで回避、これは一歩間違えるとカウンターで大ダメージを受ける隠し技なので後ろのギャラリーが拍手し出した。 俺は「うるさい、気が散る。一瞬の油断が命取り」というとギャラリーは黙った スレッドは必死にやってくるが、時既に時間切れ、スタックガードを固めた俺にスキはなかった たまに来るスタックガードでは防げない攻撃もexitで撃退、終わる頃にはズタズタにされたメモリ空間のcoreがいた
- 144 名前:名無しさん@お腹いっぱい。 mailto:sage [2008/08/10(日) 03:35:51 ]
- MTは処理効率も応答性もいいのでプログラマからは良くたよりにされる
だがたよりにされたいからMTに分けてもダメだと言う事が最近わかった MTに分けるのは真にMTの問題だから処理を分けたくて分割するんじゃない 分かれてしまう処理がMT GUIはざんねんがはっきりいってmutexはつかわないしAPIもMT-unsafeとかイマイチだから信頼されにくい
- 145 名前:名無しさん@お腹いっぱい。 mailto:sage [2008/08/15(金) 13:04:59 ]
- これ以上スレッドを作るなよ
プロセスはお前等のためにメモリ空間提供してやってるんだからな プロセスが終了すればすぐ死ぬくせに調子こき過ぎ あまり調子に乗ってると裏世界でひっそり幕を閉じる
- 146 名前:名無しさん@お腹いっぱい。 [2008/10/09(木) 04:28:39 ]
- hosyu
|

|