pthread地獄 part 2
Posixな糸に群がる亡者どものスレ。地獄の底でsage進行。 徳の高い人はpthread天国でも可。 ■前スレ pthread地獄 http://pc8.2ch.net/test/read.cgi/unix/1010933537/
(´▽`) (σσ ヘイ! Let's プログラミング! < < pthreadってもう廃れるんですかね。ってか廃れてるんですかね Boost::threadってUNIX系ではpthread使ってなかったっけ? UNIXといってもいまやいろいろあるし・・・犬糞とか 商用と非商用に分けて語ろうぜ 未だに Windows で pthread_kill() をどうやっていいのかわかんない。 って、Windows では使えないんだったけ…。 なんかそれも混乱してわかんなくなってきた…。 POSIX Parallel Programming, Part 3: Threads ttp://www.informit.com/articles/article.asp?p=686610&rl=1 OpenMPな人は何処へ行けばいいのかしらん。。。 せっかくDual Core や Quad Coreが個人でも利用できる時代になったのにい。。。 http://lists.freebsd.org/pipermail/cvs-src/2007-May/078202.html > Change the default thread library to libthr. FreeBSDのデフォルトスレッドライブラリも1:1のものに変更されました。 >>22 今までのM:Nスレッドライブラリはlibkseという名前で残っているから シンボリックリンクを張り替えるなどすればいい。 libkseは少なくとも7.x系までは生き残るだろうけど、 8-currentあたりで消されそうな気もする。 つかえないというのは いいところなしというつもりでした。 複雑な制御の割に性能が出ないのでしょうか。 Solarisも1:1になったし。 前スレで擁護してた奴の言い訳が聞きたいところだが… javaみたいにスレッドをCPU数に関係なくたくさんつくるやつの性能も1:1で満足できるのか知りたい。 言い訳よりも、ベンチの結果とかが欲しいね。 Apache (worker) + DB とかの。 SunStudio11や12もいいよ。 何せ無償だし。OpenMPもあるでよ。 いまやpthreadを生で使うことはほとんどないからなぁ。 純粋に興味があるんだけどpthread以外って何使ってる? javaのスレッド 最近はjava.util.concurrentがあるからね。 >>34 1.5の時はメモリリークに悩まされました>concurrent周り mutexを使って資源の共有ではなく、単にスレッド間の同期を取りたいのですが、 デッドロックしないようにするにはどのように書けばよいのでしょうか? pthread_barrier_waitがあるのにmutexが使いたいと申すか たくさんのthreadをpthread_create()で作成する場合、 作成した子スレッドへの引数ってどうやって渡せば良いんでしょうか? for (narg = 0; narg < 100; ++narg) { nrc = pthread_create(&t1, NULL, tfunc, (void *)&narg); } こんな感じで渡そうとしたんですが、作成された子スレッド(tfunc)側で 引数を使おうとすると、親スレッド側でどんどん値がインクリメントされて いってしまいます。(並列に動いてるんだから当然なんでしょうけど。) 値そのものをパラメータとして(void *)にキャストして渡す、 もしくはスレッド数分の配列に格納してその要素へのポインタを渡す。 というか、あなたはまだマルチスレッドプログラミングに手を出すのは早い。 そんなんではデバッグも満足にできないから、 基礎をしっかりやってからの方が近道。 >>39 レスTHX >もしくはスレッド数分の配列に格納してその要素へのポインタを渡す。 やってみたら、ちゃんと渡りました。 この時に確保しておくスレッド数分の配列って、ヒープにとるもの? それとも、親スレッド側のスタックにとるもの? それとも、グローバル変数もしくはスタティック変数としてとるもの? それとも、ケースバイケース? 子スレッド実行中にそのエリア(子スレッド用の引数エリア)が開放 されなければ良いと思うんだけど、親スレッド側のスタックにとった 場合ってどうなるんでしょうか? 親スレッドは子スレッドがすべて終了するまで存在するとした場合、 親スレッド側のスタックにとったエリアを子スレッドへの引数エリアと して使用するのはOKでしょうか? >基礎をしっかりやってからの方が近道。 今が基礎のつもりです。 このスレのタイトルは上手く考えられているな。 pthread_createでスレッドに渡す引数の渡し方を人に聞くというのは、 地獄に入口から一歩入ったところで、番犬ケルベロスに向かって 「この先にお弁当屋さんはありますか?」と聞いているような、不思議な感じが醸し出される。 >>40 実際のメモリマップを想像すれば、答えは自ずとわかる。 MTは単一のプロセス空間内でPCとスタックを複数切り替えるだけで、マジックはない。 void*に入るなら、キャストして渡した方が後のこと考えないで良いから楽ちん。 親のスタックに取ったら、その寿命考えないといけないから面倒。 個別にヒープにとってアドレス渡して、その領域の後片付けも子スレッドがすれば良いんじゃない。 場合によっては、1スレッドに必要な領域*スレッド数をまとめて取って、 子スレッドがすべて終了したら、親がまとめて捨てても良いと思うけど。 pthreadsなんで単純なsleep/wakeupインターフェースないのん? >>43 mutexを直前まで持ったままsleepできないとwakeupの取りこぼしがおこるから。 基礎から勉強しなおしてね とりこぼしちゃまずいなら、μITRONのwup_tskみたいにキューイングすればいいじゃない マルチスレッドプログラミングに関する書籍で良書と言われている ものってどんなものがあるんでしょうか? この本は良いよってのがあれば紹介して頂けると嬉しいです。 Patterns for Parallel Programming javaだけど Java並行処理プログラミング Doug Leaも書いてる 外部のカウンタ変数をひとつ用意して、 複数のスレッドで、それをインクリメントするだけのときも mutex使った方がいいのでしょうか。 extern int i; foo() { ... i++; /* is it atomic? *? ... } が atomic operation かどうかは処理系による。 ++/-- だけなら mutex よりも semaphore の方がいい気がする。 cf. sem_init(3) >>52 IA32ですら、その手のことをアセンブリ言語レベルで正しく実装する場合に LOCKプレフィクス付きでインクリメントしなきゃならなかったりする。 何らかの排他制御は必要。 インクリメントするのが一人なら確かに十分。 mutexはまあ確実だけど、性能の要求によってはspinとかrwlockとか。 semaphoreは、規定回数処理するっていうならいいけど、 回数が分からない場合どうするの? 冗談なのか何なのか知らないがインクリメント対象に volatile なんて付けたら read-modify-write なコードになると思うんだが。 cond_timedwaitがシステム時刻を要求するのは問題があると思うけど、 少なくとも日本語ではそういう情報が見当たらない。 wait中にシステム時刻が変更されたらどうなるんだろう。 どう考えてもSUNのcond_reltimedwait_npみたいなのが標準化されるべきだと 思うけど、そういう動きはないんだろうか。 標準のtimedwaitでどうエミュレーションしてもバグの潰し様が無いはず。 相対値はそれはそれでまずいんだよ。 標準はなんも考えずにシステムクロックを採用してるわけじゃなくて、 あれはあれでちゃんと角度とか考えられてるんだ。 http://www.opengroup.org/onlinepubs/000095399/functions/pthread_cond_wait.html のRATIONALE読んでね。 読んだ。 >a relative time measure can be easily implemented on top of a function that specifies absolute time ダウト。任意のタイミングによるシステム時刻変更を考えれば これが実装できないから問題にしている。 現在時刻取得 -> timespec変数にタイムアウト値加算 -> timedwait()に渡す -> wait中 全ての過程で競合が発生するだろ? 時間が進むことでタイムアウトが早く発生するのはまあ、対処できる。 (無駄にコードが複雑になるけど。) しかし、時間が巻き戻ると、タイムアウトの発生が遅れてしまう。 制御が戻らないことには何もできない。 異常時に即座に実行しないといけない処理が遅れてしまう。 さらに、逆のパターンの実装は競合が発生するという主張について、 > clock_gettime(CLOCK_REALTIME, &now) > reltime = sleep_til_this_absolute_time -now; > cond_relative_timed_wait(c, m, &reltime); > If the thread is preempted between the first statement > and the last statement, the thread blocks for too long. Blocking, > however, is irrelevant if an absolute timeout is used. これもよく分からん。 このコードの間のプリエンプトが問題になるハードリアルタイムシステムなら リアルタイムOS使わないと無理じゃないの? まあ、絶対時刻指定のAPIが要らないとまでは云わない。 > An absolute timeout also need not be > recomputed if it is used multiple times in a loop これもダメ、システム時刻の変更があり得る状況では、 システム時刻によって、ある時点から何秒経過したか知ることはできない。 タイムアウト内で、条件成立前にシグナルされる可能性がある場合、 俺の場合は、仕事ではWindowsなので、GetTickCount()を使い、 システム起動からの経過時間を元に次のタイムアウト指定値を求める。 Unixならプロセスの使用時間を取得できるAPIがあったはず。 > 時間が巻き戻ると そんな運用しないのが前提じゃないのか。 普通は進み方を遅らせて徐々に合わせるか、一気に合わせるなら シングルユーザモードもしくは他にそのへんに敏感なプロセスが 動いていないときにするものだと思うが。 返事が遅れました。 やはり何らかの制御が必要ということですね。 みなさん、ありがとうございました。 もっと勉強してきます。 >>62 そういう常識?が通用する業界もあるんだ。 言いたいことはわかるけど、pthreadなんぞ知ったこっちゃない オペレータやユーザにそんな制限かけられないことが多いのでは? 全然別のこと担当してる同じマシン上のプログラムに制限かけたり こっちから監視したりとかも無理な相談だなあ。 これがもしも、普通の個人がPCで使うソフトなら、 どのプログラムがpthread使ってるとか関係なく、 好きなときに時刻の調整くらいするよね? >>61 お前みたいな奴が、cond_relative_timedwait()で1秒って指定したのに 1.1秒で復帰してきた!クソが!って怒るから絶対時刻にしたんだよ。 pthreadsの待ちの時間の正確性なんて信頼できないんだから、この点について 議論してもあまり意味ないと思う。 >>65 信頼できない、のレベルによるな。 俺の仕事では1秒以下のズレは全然許容できるレベルだな。 それ以下はリアルタイムOS使う世界だと思う。よく知らんけど。 タイムアウト1秒に指定しても、制御戻るのは1分後かも・・・なんてのは全く話にならない。 >>64 だから、通常の運用だと ntp がゆっくり時間補正するようになっている。 >>62 の後半は例外的な運用だろ。 # 知識, 理解力, 謙虚な心 の全てが欠如してると今後辛いぞ。 そりゃ、運用や通信プロトコルまで口出しできりゃ、なんでもできる。 あんまり具体的な例挙げても仕方ない気がするが、 半導体業界の某標準プロトコルで、工場のホストから受け取った時刻に 工場内の装置(OSは普通Windows)が問答無用で同期することは普通に行われている。 Linuxに移行したいとか軽率に言い出されるとやばいと思う。 時刻なんて人間に表示するためのもので 制御プログラムとかが依存していいもんじゃないと思うんだが。 >>68 はまるで自分の業界がスタンダードで世界中がそれを基準にすべきと いわん勢いだけど、それが根本的に噛み合ってないといいかげんに気付いたらどうよ。 >>68 そう言う特殊な要件があるなら、それに合うように作ればいいだけ。 ホストの時刻に影響されたくなければ、システム時刻とホストから受け取った 時刻を別々に管理するとか、やりようはいくらでもあるだろ。 >>68 なんだ、ただのシッタカだったのか、お前。 > 半導体業界の某標準プロトコルで、工場のホストから受け取った時刻に > 工場内の装置(OSは普通Windows)が問答無用で同期することは普通に行われている。 自分で書いているように、それはパソコン系の「普通」であって、 UNIX界隈の人間がその種の運用をすることは100%有り得ないから、 時刻が急に巻き戻ってタイムアウトまで1秒のはずが61秒かかっちゃったりする心配を あなたがする必要はない。 もしプロトコル上、工場のホストと同期する必要があれば、 システムクロックを変更するのではなく、 アプリケーションの実装でシステムクロックとリモートホストのクロックの差を管理する。 このようにUNIX系へ移行するとしてもちゃんと問題なく出来るから、 あなたは心配しなくてよい。 POSIXがatomic increment/decrementをAPIとして規定しなかったのはなぜ? mutexがあっても軽量なカウンタが不要になることはないわけで、 結局、みな独自に実装しているのだが。 ここで聞かずpthreadsのインタフェースを決めた人に聞いてください。 そういうAPIが必須ならプラットフォームを変えることを検討してください。 どうしてもpthreadsに必要ならpthreadsを変えるべく努力してください。 それもいやなら文句言わず今使えるもので実装しなさい。 > アプリケーションの実装でシステムクロックとリモートホストのクロックの差を管理する。 俺が知りたいのは、特定の仕様のシステムを実現する方法じゃなくて、 他のプログラムが何していようが、 ユーザが好き勝手に時刻を変更しようが、 現在からN秒以内に条件が成立しなければ、アウトという監視は本当にできないのかってこと。 Pthread標準の枠内で。 時刻をいじってるプログラムと密に連携したり同期とれるとか、 そんなこと当てにできないし、したくもない。 ああ、わかった。 要は、pthread の仕様バグを見つけた俺を誉めてくれと言うことね。 「お前は、偉いよ。」 これで十分だろ、もう出てくるな。 だいたいUnixで「ユーザ」が時刻を好き勝手にいじれるわけねーだろ。 そういう権限を生身の人間に与えちゃってるとしたらその時点で頭おかしい。 > そういう権限を生身の人間に与えちゃってるとしたらその時点で頭おかしい。 ちょっ、お前ン所のサーバー管理者はロボットかよ !! サーバ管理者が時刻を好き勝手にいじるような頭の沸いたサイトはどうにもできねーよ。pthread以前の問題。 >>74 POSIXで規定されなかった理由は知らんが、 C++0xではちゃんと Atomic operation や Memory barrier が 定義されるから安心しろ。 ちなみにWin32のWaitForMultipleObjectsは相対時間指定なので >>59 の"Timed Wait Semantics"に挙げられた問題が存在する。 >>61 をみると理解できていないようなので、何が問題なのかわかるまで考えた方がよいだろう。 プロセスのプリエンプション自体が問題なのではないので、絶対指定のPOSIXにはこの問題はない。 Cに入れるようなもんじゃないだろう。 pthread_xxx_npあたりでいいよ。 CASとかもセットで。 >>85 pthread_xxx_npあたりで頼む Solaris10なんだけど、マルチスレッドのプロセスからコールされる サブルーチンをコンパイルする時って、どんなコンパイルオプションを 付ければ良いんですか? 普通に、コンパイルして共有ライブラリを作ればよい? このサブルーチンの中では、pthread_XXXはコールしていないので、 #include <pthread.h> もしてないんですがこれってダメ? ちなみに、そのサブルーチンは複数のスレッドから同時に呼ばれても 大丈夫な様に作ってあります。 なにもいらないと思うけど。 引数だけで計算して値を返すとか、完全に状態に依存しないものならね。 Sun cc使ってる場合は-mtが必要になったりする。 http://docs.sun.com/app/docs/doc/819-0390/compile-94179?a=view これは-D_REENTRANT -lthreadと等価なようだ。 gccであっても、使っているライブラリによっては、同様に何らかのシンボル定義が 必要になるかもしれない。 int f(int a, int b) { return a + b; } でも? gcc風に言えば__attribute_((const))な関数なら特別なコンパイラフラグは不要。 複数のスレッドの終了を待つってどう書くんですか? マルチプロセスだと、waitpid(2)とかで複数の子プロセスの終了を 待てるんですが、pthread_join()だと、特定のスレッドの終了しか待てません。 例えば、 100個の子プロセスを作成して、親プロセスはwaitpid()で任意の子プロセスの終了を 監視していて、特定の子プロセスが死んだ場合に、そのプロセスの再起動(fork())を 行うという処理を、pthreadで書こうとした場合、どうすれば良いんでしょうか? そもそも、上記の様な考え方は、プロセスの親子関係が前提となっているので、 この考え方を、親子という関係のないpthreadに持って来る事がおかしいのでしょうか? 死ぬとき親に何か通知したら? 勝手に死ぬなら、たまにpthread_kill(thread_id, 0)するとか。 それだと、作成したスレッドが死ぬようなイベントが発生したタイミングを 捕まえるという動作ではないですよね。(ポーリングっぽい) 例えば、100個スレッドを作って、その各スレッドがTCPソケットを使って 通信していて、TCPコネクションがcloseされたので、pthread_exit()を コールしたとか、、ソケットから受け取ったデータを処理している最中に SIGSEGVで死んだとかした場合に、これら100個のスレッドを常に監視 していて、死んだスレッドを再度作成したいって感じの処理をすっきりと 書きたい場合ってどうやるんでしょう? スレッドじゃなくてプロセスだったら、子プロセスがexit(2)した場合も、 子プロセスが、SIGSEGVで死んだ場合も、親プロセスがwaitpid(2)してれば 子プロセスが死んだタイミングで親プロセスはそれを知ることが出来るじゃ ないですか。 これと同じような事をpthreadでやりたいんですが、なんかよく判らんのです。 SIGSEGVなどで「死ぬ」場合はプロセスごと道連れなので、pthreads的な対処は 無意味では? そう考えていくと、スレッドが自発的に終了するケースだけを扱えばいいわけなので、 (スレッドプール的な構成なら)条件変数での通知・待機を使えばよさそうに思う。 そう。プロセスと異なり、スレッドは勝手に死んだりしない。だから終了を監視する 必要もない。個々のスレッドは処理が終わったら終了するのではなく、次の処理要求 を待って休眠するように書く方がよいだろう。 >>96 >>97 確かに、SIGSEGVなどで死ぬ場合は、SIGSEGVを発生させたロジックを実行中のスレッド のみが死ぬわけではなく、プロセス自体がいなくなりますが、これをハンドリングして 特定のスレッドのみを再起動して処理を継続するってのは変でしょうか? プログラムのバグも含めて考えると、やっぱりスレッドがSIGSEGVするケースも考慮して おきたんです。 Webサーバの様なプログラムをマルチスレッドで書くとすると、クライアントから送られて来た データがメタメタでサーバ側の処理がSIGSEGVしてしまったとか。(だったらちゃんとデータを 処理する前にチェックしろってのは、ちょっと置いといて。) こういったケースで正常なクライアントとのコネクションも全部潰れてしまうのは、なんだかなぁ って思ったんです。 あと、条件変数でスレッド間で待ち合わせを行うってのはなんとなく判るんですが、 それと、スレッドの終了を待つってのがどうもうまく結び付きません。 例えば、 ワーカースレッドがもうダメポってpthread_cond_signal()をコール。 メインスレッドは、pthread_cond_wait()で待ってる。 ワーカースレッドはどのタイミングでpthread_exit()をコールすればいいの? メインスレッドは、どのタイミングでpthread_join()をコールすればいいの? ワーカースレッドが居なくなったタイミングって条件件数を使えばメインスレッドで 捕まえることって出来ますか? なんか、この辺りがよく判らんのです。 不正なポインタが使用されないよう入力の厳密なチェックを追加するか、普通 にプロセスで書くのをお薦めする。Apacheでも普通に使われているのを見れば わかるように、UNIXのプロセスはそれほど遅くない。 どうしてもpthreadで書きつつsignalが捕捉したいのなら止めないが、 "pthread地獄"のスレタイは伊達や酔狂ではないので。 >>98 SIGSEGVを発生させるようなことをしたスレッドを、どうやって特定する? たぶん難しいと思うから、そんなの実装するよりは真面目に入力のチェックを 実装した方がずっと簡単だと思うけどなぁ。 内部だけで使うプログラムならいいけど、セキュリティ的にもあれだし。 >>101 いちおうSIGSEGVは「踏んだ」スレッドに飛ぶのでそれはわかる。 たぶん、正しくリソースを解放して終了するのが難しい。 >>100 >>101 ワーカースレッドとは別にsignalをハンドルするスレッドを、1つもしくは、 ワーカースレッド数分作成しておけば、どのワーカースレッドがSIGSEGV を発生させたかは判るような気がしてます。 とりあえず、signalはちょっと置いといて、複数のワーカースレッドが 居なくなったタイミング(pthread_exit()をコールしたタイミング)で メインスレッドがpthread_join()をコールする仕組み(=waitpid())を 作ってみたんですが、単純にpthread_cond_signal()をワーカースレッドで 呼ぶだけだと、メインスレッドがpthread_cond_wait()を実行中じゃない ケースでとりこぼしちゃうんですね。 メインスレッドがちゃんとpthread_cond_wait()を実行しているタイミングを ワーカースレッドが認識しないとダメなのか。 なんか、基本的な考え方が間違っている様な気がしてきました。 そもそも、pthread_join()が複数のスレッドを待てない時点で、この様な 事をやりたいという考えがそもそも変な気がしてるんですが、でも、 Windowsなんかのスレッドだと出来るらしいし。 端的に言えば、基本的な考え方が間違ってるよ。 別に間違ってちゃいかんというわけではないが、そっちは地獄方面。 >>102 1:1な実装とかだと、踏んだスレッドにSIGSEGVが飛びそうなのは想像できるんですが、 それがどういうレベルで保証されてるか、もし知ってたら教えて欲しいです。 SUSとかの仕様でそのあたりの挙動は定義されてましたっけ? >>105 どういうレベルかと言われると良く判らないのですが、 SIGSEGVとか、SIGILLとか、SIGFPEとかのシグナルは、同期シグナルと呼ばれていて、 スレッド側で、signal(3)でハンドラを設定しておいてあげれば、そのシグナルを発生させた スレッドがシグナルを受け取ってくれるみたいです。 "pthread 同期シグナル" でぐぐった時の2ページ目の最後のマルチスレッドのプログラミング というSunのPDFへのリンク先の資料に書いてありました。 Solaris10(x86)と、FreeBSD(i386)でサンプルを作ってみたところ、スレッド側で定義した シグナルハンドラでpthread_self()すると、ちゃんとしたスレッドIDが取得できました。 ちゃんとしたスレッドIDってのは、SIGSEGVを発生させたスレッドIDって言う意味です。 >>106 ありがとうございます。 comp.programming.threads FAQにも、 Q40: Which signals are synchronous, and whicn are are asynchronous? というのがあって、同じような記述がされてました。 POSIXとかの仕様として挙動がちゃんと決まっているなら、安心してこの性質が使える と思うのですが、実装依存と言われると便利だけど使いにくいなぁと思ったもので… 使うべきなのは条件変数じゃなくてセマフォ。 子スレッドは終了時にsemaphoreを解放して、 管理スレッドはsemaphoreを得てスレッド作ればいいだけの話。 シグナルハンドラから安全にpthread_*呼び出せるかどうかは知らんがな。 やろうとも思わん。 条件変数とmutexがあればセマフォも実装できるから同じことだよ。 mutex で保護したカウンタを、スレッド数で初期化して作っておいて、 待つ側のスレッドはそのカウンタが0になるまでpthread_cond_wait()、 終了するスレッドは、pthread_exit()する直前にカウンタをデクリメント、 もしカウンタがゼロになったらpthread_cond_signal()すればいいだけ。 かんたん。 pthread_join()は使う必要ない。 あとSIGSEGVが起きているということは、そのプロセス内のメモリ空間は ぶち壊れて不整合が起きているってことだから、さっさとプロセスごと 死ぬべき。そんな状態で動作を続けたら、誤動作して余計悲惨なことに なるのがオチ。 まあ、世の中にはsigaltstack(2)というものもあるわけでね。 SEGVから戻ってこれるケースもあるわけで、そこまで言いきるのはどうかな。 確かにそういうケースもあるにはあるな。 >>98 は明らかにそういうケースじゃないけどな。 複数のワーカースレッドの終了を待つロジックを書いてみた。 /* 全てのワーカースレッドの終了を待つ */ 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); こっちがワーカースレッド側 /* メインスレッドに処理終了を通知 */ 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); やっと、条件変数の使い方が判った。 添削してもらおうとは思ってないけど、とりあえずいろいろ教えてもらったので 張っときます。 複数の子プロセスの任意のタイミングでの終了を親プロセスが待つって いうケース(親がwaitpid(2)で任意の子プロセスの終了を待つ)を想定してます。 子が正しく死ぬなら、semaphoreでやるのが楽そうではある。 セマフォでやるってのがいまいちピンと来ないんだけど。 親(メイン)スレッドがいつ居なくなるか判らない複数の子(ワーカー)スレッドの終了を待っていて どれかの子(ワーカー)が居なくなったら、それをハンドリング(どの子が居なくなったかを認識)するってどうやるの? わかりにくいし余計なスレッド起床も伴うから 条件変数は使いまわさず親スレッド起床用と子スレッド起床用とで分けた方がよくね? 勘違いしてた。単純に死んだのを取りこぼさずに知りたいわけではないのか。 じゃあやっぱcondかな。 作ってdetachして放置。 子から親になにか渡さないといけないなら、親側に渡してから死ぬ。 子スレッドの数だけ充足するならsemaphore、 ハンドリングまでするならqueueだな。 どちらもmutexとcondition variableで書けるのはいいとして、 pthreadでの標準的な実装はないのかな? >>118 最初はそう考えたんですが、親がcond_waitしてないときに子が親にcond_signal するケースを考えると、なんか余計に複雑になるような気がして、 >>113 >>114 に落ち着いたんです。 条件変数分けると、mutexも分けないといけないし。 (ん? 条件変数だけ分けてmutexは使い回せばよい?) もっかい考えてみる。 >>120 ケースバイケースだと思うんだけど、pthreadでプログラム作るときって、detachするのが どっちかと言うとデフォなの? >>121 そうなんですよね。 こんなのって定石だと思うんですが、なんでpthread_XXが無いんだろう? >>121 >ハンドリングまでするならqueueだな。 あー、確かに、queue作って、子が死ぬ前に突っ込んで親がそれを拾えば うまくいきますね。 子が居なくなるのと親がそれを検出するのの同期を取らなくても良い場合は、 それが一番良さそうな気がしますね。 >>121 セマフォは普通にPOSIXのセマフォ使えばいいよね >>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); pthreadとシグナルについてですが、 同期シグナルは発生要因となったスレッドに送られ、そのスレッド上でシグナルハンドラが起動される。 非同期シグナルは、それを受け取る準備をしているスレッドに送られる。(結果的に、同期的にシグナルを扱うことが出来る) いずれの場合も、シグナルを受け取ったスレッドでpthread_XXを使ってもうまく動くと思うんですが、間違ってますか? ようは、SIGSEGVのハンドラからpthread_XXを呼んでみるとうまく動いているように見えるんだけど、 これって、実装(環境)依存なだけなのか、そうでないのかが知りたいんです。 実装依存以前どころか、たんに運がいいだけである可能性が高いな。 SIGSEGVが起きる状況の場合、SIGSEGVのきっかけとなったメモリ破壊の結果、 pthread_mutex_tやpthread_cond_tまで巻きぞえをくらって壊れている可能性 がある。その状況でpthread関数を呼んでちゃんと動く保証なんてありえない。 シグナルハンドラから呼ばれて正常動作する保証があるのは、マニュアルに async-signal-safeと明記されている関数だけ。 そういう関数は、実際のところはシステムコールであることが多い。 確かにそういうケースだとpthread関数がまともに動く可能性はないかもしれないですね。 私がSIGSEGVを発生させたパターンは単に、NULLアドレスに書き込んでるだけなので、 その辺のデータ(pthread関数が使用している内部データ)を壊してるって訳ではないです。 そもそも、シグナルハンドラからPthread関数が呼べない理由ってのは何故なんでしょう? Pthread関数の内部データはそのスレッドのスタック上に存在していて、 シグナルハンドラはスレッドとは別のスタックを使って実行されるからって事ですか? 仮にシグナルハンドラからpthread_*が完全に問題なく呼べたとしても、 mutexとかのリソース持ってる状態でシグナル発生したら状態復旧は絶望的だお。 そこまで苦労してまでバグを直接修正したくない理由の方に興味がわいてきた。 今、気になっているのは、Webサーバの様なサーバプログラムで、ボスは常にaccept()待ち。 クライアントからの接続があったら、ワーカーを起動して、そのあとの処理はワーカに任せる。 といった、定番的なネットワークサーバを書く場合に、いわゆるfork()モデルと、スレッドモデルで どのような差があるのか(特にエラー発生時において)という事です。 なので、ワーカー側の処理ってのは、基本的に独立していてワーカー同士で共有を行うデータも 不要であると考えています。 非同期シグナルも使う必要は無いと考えています。(多分) fork()モデルの場合は、ワーカプロセスが同期シグナル(SIGSEGV,SIGILL等)を発生させたとしても、 他のワーカープロセスへの影響は特に無く、再度クライアントが接続してくれば、また、サービスを 再開することが出来ます。 スレッドモデルで同じことを実装することは可能なのか? 特定のワーカーが何らかの理由で同期シグナルを発生させた場合、その特定のワーカが死ぬのは しょうがないと思うんですが、他のワーカーまで道連れにしてしまうのは避けたいと思っています。 スレッドモデルを使ってこのような処理を安全に書けないって事は無いんじゃないのって思うんですが、 いかがなもんでしょう? また、MySQLはマルチスレッドで動いているらしいのですが、こういったDBサーバは更に複数のワーカ間で データの排他や同期を取る必要があると思うんですが、こういったプログラムは同期シグナルとどうやって 折り合いをつけているんでしょうか。 これがいわゆる茨の道ってやつですか? >>131 まだ、なにも作ってないですよ。 pthreadというか、マルチスレッドのプログラムを作るのが始めてなので、 いろいろサンプルを作って勉強している最中です。 このスレとっても勉強になります。 レスしてくださっている皆さんありがと。 ところで、本屋行っても、pthread(マルチスレッド)に関する書籍ってほとんどないですよね。 あっても、10年ぐらい前に出版されたものが殆んどで。 この先、CPUはメニィコアに進もうとしているからもっと沢山あっても良いと思うんですが、 pthreadってあんまり使わないんですかね? > スレッドモデルで同じことを実装することは可能なのか? 想定しているのがSIGSEGVやSIGILLのようなプログラムロジックの バグである限り、不可能というのが答。 プロセスには、スレッドに比べて、メモリ空間が分離されていて SIGSEGVやSIGILLのような誤動作の影響を完全に排除できるという 特徴がある。つまり、まさにプロセスの利点に当てはまるケースな わけで、このような想定状況で、スレッドにプロセスと同等の信頼性 を求めることはできない。 > こういったプログラムは同期シグナルとどうやって折り合いをつけて > いるんでしょうか。 バグが原因で発生するシグナルは別として、sigwait() で対処するのが常識。 >>134 そっか。 やっぱりそうなんですか。 非同期シグナルであれば、シグナル受け専のスレッドを立てておいて、そこで sigwait()するってのは判るんですが、同期シグナルはsigwait()では待てないですもんね? ん?待てるのか? ちょっと試してみる。 でも、待てたとしても、どのスレッドがその同期シグナルを発生させたかって、シグナル受け専 スレッドで判らないけりゃどうしようもないですし。 悪いこといわねえだ。signal扱いたいならprocess村に帰った方がええ。 libevent はマルチスレッド環境でも安全に使う方法があるってだけで、 それ自体がスレッドセーフな作りになってるってわけじゃなかったはず。 とりあえず、やってみました。(Solaris10 x86です。) ボス側で全てのシグナルをブロックし、シグナル受信専用スレッドを作成し、そこでsigwait()。 ワーカースレッドでSGISEGVを発生させるために、NULLアドレスに書き込み。 結果は、プロセスごと終了。 同期シグナルは発生元のスレッドに送られるのでシグナル受信専用スレッドでsigwait()していても 捕まえる事が出来ないってことですね。 同期シグナルは、ワーカースレッド側でsigset()して、シグナルハンドラ側でボスに >>125 すれば、 とりあえずハンドリングは出来ますが、 >>127 にもあるように、どこまで動くのかは不明ですね。 >>134 にもあるように、この辺りがマルチスレッドと、マルチプロセスの差という事なんですね。 そもそもスレッドってなに?、スタックとスレッドの関係って?、プロセスとスレッドの関係って? OSはスレッドをどう認識してるの? なんてことが判っている人にとっては自明なんでしょうが、私にもようやくこの辺りが判って来た 様な気がします。 なかなか使いどころが難しいですが、面白い仕組みですね。 シグナルのことを考えるとunixでスレッドをモリモリ使うのはキツい。角度とか。 あと、子プロセス生成(fork)も相性が悪くて、深い悲しみに包まれた。 マルチスレッドプログラミング→排他漏れ続出→永遠とバグが取れない→いくえ不明 俺はマルチプロセスを使い手なんだが相手が残念な事にスレッドを使ってきたので「お前それで良いのか?」と言うと「何いきなり話かけて来てるわけ?」と言われた。 俺の弟がスレッドの熟練者なのだがおれはいつも勝つから相手が気の毒になったので聞いただけなんだがむかついたので「お前シグナルでボコるわ・・」と 言ってmain直後に力を溜めてkillしたら多分リアルでビビったんだろうな、、pthread_sigmaskしてたからサスペンドしてカカッっとforkしながらkillしたらかなり青ざめてた おれは一気にlongjmpしたんだけどスレッドが硬直してておれの動きを見失ったのか動いてなかったからコマンド投下で排他を崩した上についげきのデッドロックでさらにダメージは加速した。 わざとセマフォをとり「俺はこのままタイムアウトでもいいんだが?」というとようやく必死な顔してなんかコードのはしっこからブロック型システムコール出してきた。 おれはselectで回避、これは一歩間違えるとカウンターで大ダメージを受ける隠し技なので後ろのギャラリーが拍手し出した。 俺は「うるさい、気が散る。一瞬の油断が命取り」というとギャラリーは黙った スレッドは必死にやってくるが、時既に時間切れ、スタックガードを固めた俺にスキはなかった たまに来るスタックガードでは防げない攻撃もexitで撃退、終わる頃にはズタズタにされたメモリ空間のcoreがいた MTは処理効率も応答性もいいのでプログラマからは良くたよりにされる だがたよりにされたいからMTに分けてもダメだと言う事が最近わかった MTに分けるのは真にMTの問題だから処理を分けたくて分割するんじゃない 分かれてしまう処理がMT GUIはざんねんがはっきりいってmutexはつかわないしAPIもMT-unsafeとかイマイチだから信頼されにくい これ以上スレッドを作るなよ プロセスはお前等のためにメモリ空間提供してやってるんだからな プロセスが終了すればすぐ死ぬくせに調子こき過ぎ あまり調子に乗ってると裏世界でひっそり幕を閉じる >>149 FILE* p = popen("ps aux", "r"); while(fgets(buf,sizeof(buf),p)){ ... } >>150 それプロセスの一覧じゃね? だいじょうぶ? スレッド内からforkしたらセマフォとかって受け継がれんの? >>149 大抵のpsにはスレッド(LWP)も表示するオプションがある。 >>152 引き継がれるから問題が起きやすい。 ttp://d.hatena.ne.jp/yupo5656/20040715/p1 ttp://www.opengroup.org/onlinepubs/009695399/functions/fork.html * forkして作ったプロセスはsingle threadだよ。 * マルチスレッドプロセスからforkすると、fork呼んだスレッドひとつとmutexの状態とかも含めてプロセス空間が複製されるよ forkallというスレッド丸ごとforkするのは却下されたってあるね。 >>153 なるほど、forkしてすぐexecなら問題ないけどそれ以外なら死ぬのんか system関数がNGなのはここでひっかかるんかな pthread_createで作られたスレッドをptraceで追いかけたいんだけど どうしたらいい? >>156 ptrace の p は process の p。 SEGV って嫌われてるのな。 昔 mmap(2) した後に mprotect(2) して SEGV 捕捉しながらキャッシュを昇格させる ような DB 作ったなぁ。 いやいや、pthreadで出来たスレッドってプロセスみたいなもんじゃん。 straceで追うときは、-fか-Fをつければ追えるし。 やっぱstraceを気合い入れて読むしかないのかなぁ・・・嫌だなぁ・・・ プロセスみたいじゃないよ? Linuxは、なんかごっちゃにしてるとこあるけど NetBSDでも light-weight process だな。 Linux、psで表示しないだけで内部的には完全にプロセスだよね。 メモリがちょいっと共有されてるだけで Linuxのスレッドって、昔は psで普通に複数プロセスに見えてたし、 今でも中身は基本的にそれと変わってないね まあ、誰も困ってないようだから、そういう実装もアリなんだろうけど ちょっと前の仕事でスレッドプール実装した時のテスト ケースで、FreeBSD だと数千位作れたのに Linux だと 数百でアウトだったのは多分その辺の何かが影響してる と思う。 >>164 そりゃシステムで上限決めてっからだよ ulimitコマンドとかでGENKAI TOPPAしる >>165 だからその辺の上限の根拠が、って話だよ。 >>164-166 絶対違う。 賭けてもいいぜ。 >>164 は32bit環境で、かつ、各スレッドのスタックサイズをデフォルトのままで試してるから。 >>164 のような制限として、確かに他の理由もあるが そんなに少なく制限され、しかもあからさまな差がつく理由なんて一つしかない。 (デフォルトで)スタック10Mの32bitOSで各プロセス最大何スレッド程度作れるか 同じく1MのOSでは各プロセスで計いくつか ちょっとだけ考えてみな。 じゃあ Linux のスレッドサイズの由来は何なのさ。 >>168 1プロセスあたりのスタックサイズを継承すっから そのデフォルトが由来じゃね? linuxのスレッド数の上限が「linuxではスレッド ≡ プロセス」である事に 起因しているという主張は、プロセス数の上限も数百であるという事と同値。 ところがそんな(数百)プロセス数制限はない。 よって、>>164 の主張は間違っている。証明完了。 実験だけで終わらせ、真の原因を突き止めようとしないのはB級エンジニア。 >>162 > Linux、psで表示しないだけで内部的には完全にプロセスだよね。 いつの時代の話だw >>164 7,8年前から性能も大逆転だが? >>172 >いつの時代の話だw 違うの?だって隠しプロセスIDを指定してstraceで追うとか出来るよ? 概念的にはともかく実装上はプロセスの延長かと思ってた。 なんか実装上で「ほらここ見ろ」って場所教えてください。 >>172 つ ttp://www.ibm.com/developerworks/jp/linux/library/l-linux-kernel/ プロセス管理は、プロセスの実行に集中的に取り組みます。カーネルではプロセスは スレッドと呼ばれ、プロセッサーの個々の仮想化 (スレッド・コード、データ、スタック、 および CPU レジスター) を表します。ユーザー空間ではプロセスという用語が一般的に 使用されていますが、Linux 実装ではこの 2 つの概念 (プロセスとスレッド) を 区別していません。カーネルは SCI を介して、新規プロセスの作成 (fork、exec、または POSIX (Portable Operating System Interface) 関数)、プロセスの停止 (kill、exit)、 そしてプロセス間の通信と同期 (信号、または POSIX メカニズム) を行うための アプリケーション・プログラム・インターフェース (API) を提供します。 >>170 > ところがそんな(数百)プロセス数制限はない。 メモリ量に依存するけど? http://www.gelato.unsw.edu.au/lxr/source/kernel/fork.c > max_threads = mempages / (8 * THREAD_SIZE / PAGE_SIZE); >>176 ここで process と thread に区別はないのはいいよな? プロセス数とスレッド数の合計は max_threads を越え られない。また、pthread_attr_setstackaddr() でどう こうしようがこの制限からは逃れられないので >>167 も的外れ。 これを「プロセス≡スレッドに起因してる」っていうの は、そんなに言い過ぎかね? 内部的には完全にプロセスっていうより、 プロセスとスレッドを統一的に扱っているって感じでしょ。 今は。昔は特殊なプロセスとして実装していたけど。 だからsignalの扱いが変だった。 FreeBSDはrforkとpthreadが別フレームワーク上の実装で もうちょっと整理できないのかと思う。 組み込みとかでマルチタスキングモニタ書いてた俺から すると(当然こいつも区別無かったんだが)、Linux 実 装の方がお手軽実装(悪く言えば手抜き)に見える。 それに Linux 側も最近はスレッド≡プロセスの柵から 脱却しつつあるんじゃなかったっけ? SunOSとかのLWP使ったスレッドはどうだったの? Solaris8までは、M:Nだったと言うことはスレッド≡プロセスではないよね。 >>179 脱却しようと思ったけどやっぱプロセス扱いの方が便利だから脱却やーめた って感じがする。気のせいかもしれないけど。 ん、結局、今はスレッドに軽量性というメリットは 無かったりするの? あるよ。 カーネル内でプロセスと似た処理していることと、 軽量かどうかは全く関係ない。 >>185 似たような処理をしているなら似たような重さになるんじゃないの? なんで速く処理できるの? ぶら下がるリソースが違うから。 rforkを勉強してみたら? >>187 ありがとう。Linuxではまだ関係ないってことだね。 SMP 対応前後くらいで thread の扱いも大分違うんじゃ ないかと思うんだけどどうかね? > 識者 それ以前はユーザプロセス空間内で閉じたスレッド機構 もそれなりにあったと思うんだけど、流石に SMP とな るとスケジューラの管理下に入れないわけにはいかない だろうし。 そう考えると Linux とそれ以外では同じ形態を目指し ていてもアプローチの仕方が正反対なんじゃないか? >>183 的なのもそこに理由がある気がする。 >>189 > そう考えると Linux とそれ以外では同じ形態を目指し > ていてもアプローチの仕方が正反対なんじゃないか? なにも変らないよ。 >>189 C10K問題 ttp://www.hyuki.com/yukiwiki/wiki.cgi?TheC10kProblem が提唱された あたりから、複雑怪奇な割に性能が上がらないM:Nモデルから、単純明快な1:1モデル へと向かうOSが増えたのは確か。 あと、プロセスとスレッドとを同じように扱うか否かはNUMAみたいなアーキテクチャを どう考えるのかにもよりそう。 >>191 面白いね。 FreeBSD はその後に SMPng の作業を完了しているから 現状を見てみたいけど、それぞれの OS が同期を取って 開発されているわけじゃないからどのタイミングで評価 するかってのは難しい問題だな。 >>191 WebサーバがPC UNIX系の主戦場になったからね。 I/Oセントリックだとカーネルスケジューラが有利。 システムコールの中でスケジュールしたいから。 めちゃくちゃ古い実装ベースの情報ではあるけど、 www.acme.com/software/thttpd/benchmarks.html の一番下にある表は、結構面白いとこ突いてるいるように見える。 node.jsとか、非同期通信寄りが増えてきたな。 pthread_createで300前後しかスレッドを吐き出せないのだが・・・。 もちろん、pthread_detachを使ってデタッチしてるんだけど、全く増える気配なし。 Linuxの設定を見てみると、システム全体のスレッド上限が9万、ユーザーが4万5千 お手上げ状態です。 Stackのサイズを変更したら、すんなり3万2千くらいまで行けました。 どうも、お騒がせしました。 pthread_mutexで複数のスレッドが待ち状態のとき、起床するのは優先度順ですか? 先に待ち状態になった順から起床させれないですか? セマフォなら待ち順になるのかな >>201 待ち順にはならぬ・・・ ならぬのだ・・・ カーネルさん「順番は俺の都合のいいようにやるから、 順序を規定したければ自分で管理しろよ。 その代わり、マルチCPUになろうがなんだろうが 俺のやることは今と変わらんから安心しろ」 スレッドの同時実行数って決められない? 同時実行数1にして似非RTOSみたいにしたいんだけど ちなみに各スレッドはsetschedpolicyでSCHED_FIFOにしてるつもりでエラーは返ってきてない 管理者で実行しているし、sched_priorityは1〜5にしてsetschedparamしてます なにか手順が足りないでしょうか? 自分でセマフォとかで管理するしかないんでしょうか? うむ、cygwinではpthread_attr系がダミー実装しかされていない >コルーチン動かせばいい これって具体的には何をすることをいってるの? 何か簡単な方法があるの? スレッド作った時点でそれってコルーチンだよな 中断再開を管理するスレッドを別に用意しろということか? いえ、こういう文脈でコルーチンといえば、 ・エントリポイントが複数ある ・コードで指定した場所で実行停止が可能な サブルーチンのことです。 「指定した場所」でCPUを明け渡しながら動きます。 哲学者の食事問題を例に取ると、全体で一つのコルーチン。 最初にどの哲学者から食事を開始してもいい。 自前でユーザレベルスレッドを作ればできるってことじゃないのかな? ready_queue/wait_queueそれからスレッドインスタンスの構造体、 あとはwait(sleep)/act(wakeup)関数を定義すればいい。 もしカーネルの内部構造について知識/技術がある人なら簡単と言えるかも。 大変かもしれんが、スレッド間の排他制御とか不要(最低限)になるから、 元の設計がしっかりしていれば、かえってデバックは楽だったりする。 今時pthreadでゴリゴリて、流行らないのかな? >>215 流行り廃りで避けられるジャンルじゃないだろこれ 代替に何使うつもりだったの? pthread直ではなく、上位のライブラリ越しにつかうとかじゃない? pthread獣を召喚するライブラリでオススメなんかある? >>218 C++11の<thread>とか、Boost::thread とか、OpenMP とか。 先日、他部署を交えて開かれた社内技術交換会でのこと。 先輩は自分が開発担当したあるソフトのプログラミング中に思いついたという 文字列処理の高速化アルゴリズムについて得意気に解説し始めた。 話し始めてしばらくして、隣の部署の人が口をはさんだ。 「それ、有名な番兵のアルゴリズムですよね。ウチでも昔はよく番兵を使いました。 でも番兵はマルチスレッドで使えないという欠点があるので、 今では番兵のアルゴリズムを使うことは禁止してます。 これ使われると発見しにくいバグになって困るんですよねぇ… ところで今日のお話というのは、 番兵のアルゴリズムをマルチスレッドに対応させるような方法か何かですか?」 そのあと先輩の話は支離滅裂になり、何の技術交換会だったのか よく覚えていない… いまさらだけど"Pthreadsプログラミング"を買ってきた がんばって積読するぞ 中略) いやいや、●流出事件でも分かった様に叩きスレが伸びるってのは理由が有る訳です。2ちゃんねる運営の金になる。 運営の工作員が自演で火を付けてるわけ、それに乗った一般人が情報出して、その情報溜め込んだ運営の工作員がその情報元にまた煽る。 2ちゃんねるの運営にはそう言う集客方法が有る訳です。 それ系のサイトじゃあ、良く語られてる『プロ固定(プロ名無し)』ですよ。 各板覗いて御覧なさい、必ずあるでしょ?個人対象にした叩きスレッドが、 内容は似たり寄ったりですよ、どのスレッドも。運営の工作員が掛け持ちでテコ入れしてますから(笑 一種の炎上ビジネスなんです。 一般利用者ってのはお手軽に誹謗中傷出来る対象があると、何も考えずに叩くんです。とりあえず多少の正当性みたいなものが有ればいい。 どんな小さな事で良いし、自分が何らかの係わりや知識が有れば尚の事。 日本最大の電子掲示板 2ちゃんねる が板によって専門的に分かれてるってのはそう言う意味でも凄く都合が良いわけです。 各専門分野の関係者が勝手に情報持ち寄って、叩く対象の情報提供者になってくれる・・・ 正にカモがネギ背負って毎日飛んで来ては個人の誹謗中傷スレッドに情報投下してスレッド伸ばしてくれてる訳です。 炎上とか本人降臨とかは運営にとってはご馳走。 巷で言われております『ネットイナゴ、無敵の人』は運営と二人三脚な所がありまして、 酷い煽り方のレスは自作自演の運営工作員だったりするんですけど、一般人のですね、例えば関係者や嫉み僻み私怨持ってる様な、 又は何だか良く分からない“正義感”に突き動かされてしまう様な程度の人も誹謗中傷スレッドの叩きの一連の流れを見るとですね。 2ちゃんねる の運営方法の一部になってるんですよ。 ネラーと運営と言うのはお互い共存共生関係に有ると、まぁ、そう言う話なわけです。 (後略 . 番兵使うとマルチスレッドでバグるって、どういうロジックなんだろうか。 誰でも簡単にパソコン1台で稼げる方法など 参考までに、 ⇒ 『宮本のゴウリエセレレ』 というブログで見ることができるらしいです。 グーグル検索⇒『宮本のゴウリエセレレ』 AUQ0EKC298 知り合いから教えてもらったパソコン一台でお金持ちになれるやり方 時間がある方はみてもいいかもしれません グーグルで検索するといいかも『ネットで稼ぐ方法 モニアレフヌノ』 1HZYE もっと整理して弱い グーナー絶頂の順位に変動あり得る)よな」みたいな なんか思ったより下げない 相変わらずツボガーは話に広がりがなくて実在の居酒屋で喜んでるだけの人エナプ公式グッズのサンダル履いてる状態なの分まで歌う」 read.cgi ver 07.5.1 2024/04/28 Walang Kapalit ★ | Donguri System Team 5ちゃんねる