[表示 : 全て 最新50 1-99 101- 201- 301- 401- 501- 601- 701- 801- 901- 1001- 2chのread.cgiへ]
Update time : 06/04 17:21 / Filesize : 278 KB / Number-of Response : 1002
[このスレッドの書き込みを削除する]
[+板 最近立ったスレ&熱いスレ一覧 : +板 最近立ったスレ/記者別一覧] [類似スレッド一覧]


↑キャッシュ検索、類似スレ動作を修正しました、ご迷惑をお掛けしました

マルチスレッドプログラミング相談室 その4



1 名前:デフォルトの名無しさん mailto:sage [2005/11/03(木) 11:23:05 ]
マルチスレッドプログラミングについて語るスレ。
OS・言語・環境は問わないが、それゆえ明記すべし。

その1 pc3.2ch.net/test/read.cgi/tech/997345868/
その2 pc5.2ch.net/test/read.cgi/tech/1037636153/
その3 pc8.2ch.net/test/read.cgi/tech/1098268137/

596 名前:デフォルトの名無しさん mailto:sage [2006/07/05(水) 11:51:06 ]
ブロッキングするべき状況と、そうでない状況がある。
前者ならブロックさせとけばいいし、そうでなければ非同期APIを使うか、
別個にスレッドを作ればいい。


597 名前:デフォルトの名無しさん mailto:sage [2006/07/05(水) 11:59:52 ]
>>593
recv()呼ぶ前にMSG_PEEKしておくなりしとかんとあかんよ。
#つーか、TCP受信処理を途中で終わらせると言う仕様そのものが如何なものかと。

598 名前:デフォルトの名無しさん mailto:sage [2006/07/05(水) 13:48:39 ]
>>595
一般的かどうかは知らないけど、普通はselect使うんじゃないかな。

599 名前:593 [2006/07/05(水) 13:49:40 ]
>>596
「強制終了」以外は普通にブロックして、データが届いたときだけ
処理してくれればいいんだけど。って状況でした。
非同期っていうと、WSAEventSelect, WSAAsyncSelectで、通知を待つって
ことでよいですよね?

>>597
ちょっとわかんないのですが、
MSG_PEEKで、受信データが無いときはどうやって次の受信データを待つのが綺麗?
あと、途中で終わらないとしたら、どうやって終わるのがよいですか?


600 名前:デフォルトの名無しさん mailto:sage [2006/07/05(水) 18:14:11 ]
>>599
WSAAsyncSelect(s, hwnd, 0, 0);
shutdown(s, 1);
while (recv(s, buf, buflen, 0) != 0) {}
closesocket(s);


601 名前:デフォルトの名無しさん mailto:sage [2006/07/05(水) 19:33:20 ]
>>600
それ先方がデータ送ってくれないとCPU100%のビジーループ。
サーバアプリでは非常によろしくないコーディング。

602 名前:デフォルトの名無しさん mailto:sage [2006/07/05(水) 19:50:55 ]
recvって、ブロックするんじゃないの?

603 名前:デフォルトの名無しさん mailto:sage [2006/07/05(水) 19:54:13 ]
スマソ。ノンブロッキングのソケットと勘違いしてた。

604 名前:デフォルトの名無しさん mailto:sage [2006/07/05(水) 20:35:06 ]
WSAAsyncSelectした時点でノンブロックになる



605 名前:593 [2006/07/06(木) 17:50:25 ]
任意のタイミングで終了させたいスレッド内では、ブロックする関数は呼ぶな。
socketはデフォルト非同期で。
で理解しました。 ありがとう。


606 名前:デフォルトの名無しさん mailto:sage [2006/07/06(木) 19:44:58 ]
>>605
そう理解したんならそれでもいいが・・・

607 名前:デフォルトの名無しさん mailto:sage [2006/07/06(木) 22:55:34 ]
ソケットを任意のタイミングで終了させると再起動したときにわややがな。

608 名前:593 [2006/07/06(木) 23:34:44 ]
>>607
どゆこと?
例えばサーバ的なアプリで、その受信用スレッドを、サーバ的なアプリ
のユーザ都合でブチっとしたくなった場合、、、
受信処理を終了させて、クローズなり何なりをしたい。
そんな場合ですが、再起動とは、ここでサーバ的なアプリを再度起動して
受信を始めようとした場合になにかが起こるってことですか?




609 名前:デフォルトの名無しさん mailto:sage [2006/07/07(金) 00:34:15 ]
下の層が受信しているのにアプリが落ちたら、次に起動するときにbindErrorになる。

610 名前:デフォルトの名無しさん mailto:sage [2006/07/07(金) 00:43:27 ]
つかさ、断片的な情報を積み重ねて信頼性のないアプリ作るよりさ、
ばしっとWinsock Programmer's FAQとか、Winsock関連書籍を読み
とおして、きちっとしたアプリを作ろうとは思わんのかね。

611 名前:デフォルトの名無しさん mailto:sage [2006/07/07(金) 01:07:01 ]
>>609
アドバイスするなら、その前にFAQくらい読んどけよ。
知識足りなさ過ぎ。

612 名前:593 [2006/07/07(金) 10:11:03 ]
>>610
終了するときは、shutdown(sock, 1) をスレッドの外から呼べ、
そうするとrecvが0返すので、スレッドを抜けろ。
で、理解しました。ありがとう。


613 名前:デフォルトの名無しさん mailto:sage [2006/07/07(金) 11:42:52 ]
>>609
100%賛成して同意して応援します。
他人のいう事に惑わされたりマニュアルやFAQを読んだりせず、
先方が送信を続けている間は終了できないプログラムを作り続けてください。

614 名前:デフォルトの名無しさん mailto:sage [2006/07/07(金) 11:56:22 ]
>>593
fcntl(s, F_SETFL, O_NONBLOCK); って使えない?
(Windowsだとこれはないのかな?)
>>595
select() 使う場合は他のスレッドが同じソケットから読まないように
作る必要がある。recv() ではあまりないかも知れないが、サーバ用に
bind() した一つのソケットに対して複数のスレッドから accept()
する場合にselect()使うとハマる(2つ以上のスレッドがselect()を通過
した場合に一つのスレッド以外がブロックする)。防止するには上に
書いたような fcntl() で O_NONBLOCK セットして accept() で止まら
ないようにする。
>>609
最初に setsockopt() で SO_REUSEADDR をセットしとけばいいんじゃないか?




615 名前:デフォルトの名無しさん [2006/07/08(土) 02:08:08 ]
volatile最強

616 名前:デフォルトの名無しさん mailto:sage [2006/07/08(土) 10:36:46 ]
メモリモデル勉強しる

617 名前:593 [2006/07/09(日) 20:09:28 ]
最後にもひとつ。
一般的に、マルチスレッドで使われることを前提にした、受信待ちのような
ブロックする関数を提供しようとした場合は、それと一緒に受信を中断
して安全に返るための、他のスレッドから呼ばれる関数(socketの場合のshutdown)
を提供すればよい。
ですか?
他に綺麗な方法あったら教えてください。


618 名前:デフォルトの名無しさん mailto:sage [2006/07/09(日) 20:26:23 ]
一般的には、recvでブロックさせるのではなく
select系でブロックさせて
selectをブレークさせる方法を使うだろ。

つまり「外部から解除できないブロッキング関数ではブロックさせない」と。

619 名前:デフォルトの名無しさん mailto:sage [2006/07/09(日) 20:28:20 ]
selectってキャンセル可能だっけ

620 名前:デフォルトの名無しさん mailto:sage [2006/07/09(日) 20:36:02 ]
selectで同時にパイプを待ったり
WSAEventSelectで同時にEventを待ったり
というやり方のこと。

621 名前:デフォルトの名無しさん mailto:sage [2006/07/09(日) 20:39:08 ]
selectでtimeout設定すればいいと思うけど
それとももっと高度な制御がしたいの?


622 名前:デフォルトの名無しさん mailto:sage [2006/07/10(月) 00:20:40 ]
>>621
timeout 値の設定がめんどい。

仕方なく >>620 の WSAEventSelect 使ってるけど、
これはこれでめんどい。

623 名前:デフォルトの名無しさん mailto:sage [2006/07/10(月) 03:56:03 ]
pselect

624 名前:593 [2006/07/10(月) 10:22:26 ]
>> 618
なるほど。
Linuxでは、読み込むものは全部ファイル(ファイルデスクリプタ)で、
中断など例外的な処理は全部シグナル。と思ってpselectで綺麗にい
けていたんだけれど、
Winにいったら、いろんな方法がありそうだけれど、どれもいまいちに見えて。。
WSAEventSelectは、socket以外にも汎用的に使ったりする?






625 名前:デフォルトの名無しさん mailto:sage [2006/07/10(月) 11:23:05 ]
>>617
スレッド(タスク)開始、実行状況(実行結果)の取得、完了待ち、中断のための関数を
それぞれ提供するのが一般的だと思います。
あと場合によっては先方のスレッドでコールバックされる実行状況の通知のための
コールバック関数なんかも設定できると UI 作るときには便利(プログレスバーとか)。

>>624
個人的な意見だけど、Windows では(ソケットなら WSAEventSelect等も使って)
(Msg)WaitForMultipleObjectExで待機、何かあれば処理するというのがマルチ
スレッドの場合の定石だと思います。
ソケットだけ相手にするなら単にclosesocketしてしまうというのもアリだと思うけど。

>WSAEventSelectは、socket以外にも汎用的に使ったりする?
ソケットを相手にしないのにWSA〜を使う局面は無いと思う。

626 名前:デフォルトの名無しさん mailto:sage [2006/07/11(火) 00:19:53 ]
>>624

Winでも sock をファイルとして扱えるよ。

627 名前:デフォルトの名無しさん mailto:sage [2006/07/18(火) 19:03:35 ]
Linux (Kernel 2.6.17) で、pthread_create() で複数スレッドを作り、
そのスレッド全てが同一の bind(), listen() されたソケットに対して
accept() を行うプログラムを作ったのですが(O_NONBLOCKなソケット
ですが)、クライアントプログラムから複数 connect() すると、
accept() が同じ値のファイルディスクリプタを返して来ます。処理を
単純に書くとこんな感じです。

for(;;) {
 int cs = accept(...); // ここで cs が別スレッドと同じ値になる。
 if (cs == -1) {
  if (errno == EAGAIN) {
   usleep(50000);
   continue;
  } else {
   break; // error
  }
 } else {
  proc(cs); // cs を使った処理。
  close(cs);
 }
}

accept() の前後に pthread_mutex_lock(), pthread_mutex_unlock() で
ロック、アンロックをしても同じでした。

これって Linux のバグなんでしょうか?
これを回避するにはやはり accept() をするスレッドを一つにしないと
駄目ですか?


628 名前:デフォルトの名無しさん [2006/07/18(火) 19:04:29 ]
すいません。質問なのに age 忘れました。age ておきます。よろしくお願いします。

629 名前:デフォルトの名無しさん mailto:sage [2006/07/18(火) 19:32:26 ]
わざわざageんなよ

630 名前:デフォルトの名無しさん mailto:sage [2006/07/18(火) 22:10:43 ]
コンパイル・リンク時のコマンドライン見せろ

631 名前:デフォルトの名無しさん mailto:sage [2006/07/19(水) 01:14:42 ]
>>627
> accept() の前後に pthread_mutex_lock(), pthread_mutex_unlock() で
> ロック、アンロックをしても同じでした。

この時点でプログラミングの問題じゃないことに気付け。

632 名前:デフォルトの名無しさん mailto:sage [2006/07/19(水) 01:56:34 ]
>>627
>これって Linux のバグなんでしょうか?
つかその前に、どこで習ったんだそんな阿呆な手順。

633 名前:デフォルトの名無しさん mailto:sage [2006/07/19(水) 02:07:07 ]
acceptしてからthreadおこせ

634 名前:デフォルトの名無しさん mailto:sage [2006/07/19(水) 03:17:38 ]
>>627
よく知らんけど、下記のApache のディレクティブの存在なんかを見ると
accept は直列化 (同時に1つのプロセス・スレッドからのみ呼ぶ)するのが
普通なんじゃないかと思うが・・・

httpd.apache.org/docs/2.2/ja/mod/mpm_common.html



635 名前:デフォルトの名無しさん mailto:sage [2006/07/19(水) 09:14:39 ]
>>630
gcc hoge.c -lpthread

>>631
どういう意味ですか? 同時に複数のスレッドが accept() しないように
しただけですが?

>>632
これは阿呆な手段ですか? 何故? その辺詳しく教えてもらえますか?
どこで習ったかは記憶にありません。ただ昔 Java で似たようなものを
作った時はちゃんと動いたと思いました。

>>633
それはつまり accept() は親(?)スレッド一つでやるということですね。


636 名前:デフォルトの名無しさん [2006/07/19(水) 10:02:36 ]
accept()を排他しても、
そのプログラムがまともにうごかん事に疑問はないのか?

他の部分がおかしいだけではないのか?

637 名前:デフォルトの名無しさん mailto:sage [2006/07/19(水) 11:14:26 ]
>>636
そこが疑問ですよ。なんで既に取得してオープンされているファイル
ディスクリプタと同じ値のファイルディスクリプタが返って来るのか
という点がね。

気になるのは Linux の場合スレッドは clone() システムコールで作った
特殊な別プロセスであるということです。別プロセスだから複数スレッドで
accept() した時に同一ファイルディスクリプタが取れてしまうんじゃない
かな、とは思ったんですが、確証がなかったので質問したんです。
(Linux板の方で質問した方がよかったかな? でも他のOSではこういうのは
できないのかも少し気になる)。

で、その後、accept() を一つのスレッドでだけやって、他のスレッドは
待機させておいて、accept() 成功後にファイルディスクリプタを待機
スレッドに渡すように作り替えたらちゃんと動くプログラムは作れました。
理由はどうあれこういう風にするか、あるいは accept() 成功後にスレッド
作るように書かないと駄目なようですね。


638 名前:デフォルトの名無しさん mailto:sage [2006/07/19(水) 11:25:03 ]
>>627
> int cs = accept(...); // ここで cs が別スレッドと同じ値になる。
本当にこれと同じ書き方だったんだな?
csが大域変数だったってオチがありそうだ。

639 名前:デフォルトの名無しさん mailto:sage [2006/07/19(水) 11:30:07 ]
>>638
いいえ。大域ではありません。autoです。


640 名前:デフォルトの名無しさん mailto:sage [2006/07/19(水) 12:26:13 ]
生半可な学習しないで、ファイルディスクリプタについてちゃんと勉強したら?

641 名前:デフォルトの名無しさん mailto:sage [2006/07/19(水) 13:35:02 ]
>>637
>スレッドは clone() システムコールで作った
ちょwwwwおまwwwww帰れwwwww

642 名前:デフォルトの名無しさん mailto:sage [2006/07/19(水) 13:56:58 ]
げ、pthread_createで作ってんじゃないのか・・・!!!

643 名前:デフォルトの名無しさん mailto:sage [2006/07/19(水) 14:24:08 ]
>>640
生半可? どの辺がですか?

>>641-642
pthread_create() で作ってますよ。clone() は内部動作の話です。


644 名前:デフォルトの名無しさん mailto:sage [2006/07/19(水) 14:29:47 ]
こいつむかつく〜☆



645 名前:デフォルトの名無しさん mailto:sage [2006/07/19(水) 14:36:37 ]
>>643
コンパイルオプションとかはどうだろう・・・ -pthread とか付け忘れありませんか?

646 名前:デフォルトの名無しさん mailto:sage [2006/07/19(水) 14:42:25 ]
>>645
>>635


647 名前:デフォルトの名無しさん mailto:sage [2006/07/19(水) 14:48:29 ]
>>643
続きは以下で。
ネットワークプログラミング相談室 Port17
pc8.2ch.net/test/read.cgi/tech/1148944560/

648 名前:デフォルトの名無しさん mailto:sage [2006/07/19(水) 14:59:44 ]
>>646
-lpthread だけ指定して -pthread を指定していないのではないか、といっているのだが。

649 名前:デフォルトの名無しさん mailto:sage [2006/07/19(水) 15:38:16 ]
>>648
-pthread は指定していませんでしたが、man ページや info 見ると
Linux では関係ないようですよ。

念のため指定してテストしてみましたが、同じ動作になりました。


650 名前:デフォルトの名無しさん mailto:sage [2006/07/19(水) 15:45:45 ]
いい加減、誰かファイルディスクリプタの説明してやれよw

651 名前:デフォルトの名無しさん mailto:sage [2006/07/19(水) 15:47:52 ]
>>647
そっちの方がいいですか?
スレッドとネットワークと Linux が混ざった疑問なのでどこがいいのか迷ったんですが。


652 名前:デフォルトの名無しさん mailto:sage [2006/07/19(水) 16:00:17 ]
>>640>>650
pthread_createで作ったスレッド間では、ファイルディスクプリタは共有されます。
すなわち、同じ数値=同じソケット端点。
何がいいたのか知らんがこれでいいか?

653 名前:デフォルトの名無しさん mailto:sage [2006/07/19(水) 16:06:07 ]
>>651
どっちがいいのかはわからんけど、このスレじゃ解決できなさそうじゃん。

654 名前:デフォルトの名無しさん mailto:sage [2006/07/19(水) 16:20:45 ]
Linuxのスレッドが特別なプロセスだったのは、2.4より前の話だよ。
# 例えばpidやsignalの扱いなど。
>>627は、2.6.17だから関係ない。



655 名前:デフォルトの名無しさん mailto:sage [2006/07/19(水) 16:21:59 ]
>>637
> accept() 成功後にスレッド作るように書かないと駄目なようですね。

そんなことはない。

656 名前:デフォルトの名無しさん mailto:sage [2006/07/19(水) 16:22:13 ]
>>652
それは知ってますよ。だからこそOSがおかしいんじゃないかと思ったんですから。

元々の質問を要約すると、まだ close() されていないファイル
ディスクリプタの値を accept() が返して来るのは何故かです。
一つのスレッドが accept() で 5 を受け取ったとして、それが
close() される前にもう一つのスレッドが行った accept() が
受け取ったファイルディスクリプタの値も 5 だったということです。
これ、accept() を一つのスレッドでしかやらなければ当然 6 などの
違う値が返って来ます。

>>653
今のところそんな感じしますね。


657 名前:デフォルトの名無しさん mailto:sage [2006/07/19(水) 16:24:17 ]
>>654-655
そうですか…。じゃあ何でだろう?


658 名前:デフォルトの名無しさん mailto:sage [2006/07/19(水) 16:26:01 ]
こっちの方がいいかも。
UNIX板 pthread地獄
pc8.2ch.net/test/read.cgi/unix/1010933537/
読んでる人はこの板と重複がかなりあるかもだけど。

659 名前:デフォルトの名無しさん mailto:sage [2006/07/19(水) 16:34:42 ]
>>658
そこはたしかに近いこと話し合われてたスレですね。
じゃあそこに移転します。

こちらのスレのみなさまありがとうございました。


660 名前:636 mailto:sage [2006/07/19(水) 23:13:46 ]
な?


661 名前:デフォルトの名無しさん mailto:sage [2006/07/20(木) 01:05:07 ]
うはwww
ボッコボコwww
しかも自分のミスwww

662 名前:デフォルトの名無しさん mailto:sage [2006/07/20(木) 12:50:33 ]
>>640>>650
お前等も黙ってないで「ファイルディスクリプタの説明」してくれよw

663 名前:デフォルトの名無しさん mailto:sage [2006/07/20(木) 13:12:28 ]
File Disk Riptor 略して FDR である

664 名前:デフォルトの名無しさん mailto:sage [2006/07/20(木) 14:35:46 ]
なんか車の駆動方式っぽい略称だな。



665 名前:627 mailto:sage [2006/07/20(木) 16:04:12 ]
申し訳ありません。私がバグっておりました。

accept() 後の処理を別関数でやっていたのですが、その中で
fdopen() を使って accept() で受け取ったファイルディスク
リプタから FILE * を作って fgets() や fprintf() を使って
いました。それでその関数から返る直前に fclose() をして
いますが、そうすると当然元となったソケットも close()
されます。

このことをすっかり忘れていたためこの別関数から戻って
来ても accept() で取ったファイルディスクリプタは
オープンしたままだと思い込み、別関数から帰って来てから
close() までの間に別スレッドで accept() した時の
ファイルディスクリプタと同じ値になることがあったため、
今回の疑問に繋がっていました。

ということでお騒がせしました。
Linux でも複数スレッドからの accept() は問題無くできます。

666 名前:デフォルトの名無しさん mailto:sage [2006/07/20(木) 16:25:36 ]
まあせいぜい地雷原を走り抜けてくれ

667 名前:デフォルトの名無しさん mailto:sage [2006/07/21(金) 20:41:07 ]
Javaだと複数のスレッドがacceptでブロックしてても動いたと思う。
ttp://www.amazon.co.jp/gp/product/4274065200/ の例の1つにあったと思う。

個人的にはとても気持ち悪いし、他の人にコードを見せると頭を抱えるし、
特にメリットも思いつかないので、
自分はJavaでもacceptは1つのスレッドで実行してる。

668 名前:デフォルトの名無しさん mailto:sage [2006/07/21(金) 20:54:45 ]
この人の場合、さらに non-blocking にしてあって、ブロックしないでポーリングしてるらしいよw

669 名前:デフォルトの名無しさん mailto:sage [2006/07/21(金) 21:16:04 ]
>>667
> 特にメリットも思いつかないので、

はあ


670 名前:デフォルトの名無しさん mailto:sage [2006/07/22(土) 00:47:01 ]
試したことはないが、
複数のThreadがServerSocket#accept()でブロックされてるとき、
ブロック解除で起こされるThreadはたぶん唯1つなのがメリットじゃないかな。
単一のThreadがaccept()待ち→ブロック解除→Queueに放り込んでWorker Threadを
たたき起こすパターンだと、Queueを監視する複数のWorker Threadがいったん
たたき起こされるから。


671 名前:デフォルトの名無しさん mailto:sage [2006/07/23(日) 09:39:44 ]
pThreadsについての書籍を探してるのですが、以下のもの読まれてる方
感想はどうですか?良書ですかね?

www.amazon.com/gp/product/1584503718/ref=pd_rvi_gw_1/103-0885486-2811001?%5Fencoding=UTF8&v=glance&n=283155

www.amazon.com/gp/product/0735710430/ref=pd_rvi_gw_2/103-0885486-2811001?%5Fencoding=UTF8&v=glance&n=283155

672 名前:デフォルトの名無しさん [2006/07/26(水) 17:24:59 ]
お世話になります。
識者のご意見ください。

以下のような状況です。(環境はVC6のWin32API)

メインスレッドAと、待機スレッドBがあります。
BはSuspend状態です。

あるタイミングでAがBに仕事を投げてResumeしました。
Bは仕事が終わったら自分でSuspend状態になりたいのです。

Bは自分のHANDLEをSuspendThreadしちゃってもいいものでしょうか?
AがBのフラグを見てSuspendしてやるというのはちょっと効率が
悪い気がします。

以前はBを待機スレッドではなく、その都度生成して自殺させていました。
が、この方法だとデバッグウインドウに生成と消滅のメッセージが
出まくるのと、やはりCreateThreadの負荷が気になります。

こういう場合の常套手段など、ご教示ください。
待機スレッドがCPUを食わないようにするために、Suspend状態に
しておく、という風に考えるのは変でしょうか?

よろしくお願い致します。

673 名前:デフォルトの名無しさん mailto:sage [2006/07/26(水) 17:36:12 ]
>>672
ただのワーカースレッドでええんちゃうかと
マイクロスレッドのようなものを考えてるなら、ファイバでも使えばいい


674 名前:デフォルトの名無しさん mailto:sage [2006/07/26(水) 17:36:23 ]
>>672
自分をSuspendするのは悪くない。というか、それが唯一のSuspendThreadの正しい使い方。
基本的には自スレッド以外をSuspendThreadしてはいけない。

ただし、普通はautoresetのイベントハンドルを用意して WaitForSingleObject で待たせておき、
SetEventで起こす。これはAがBをResumeThreadで起こすのが難しいから。

具体的には、SuspendThread/ResumeThreadで待機を実現しようとすると、
ResumeThreadするときに、ちょうどBが何かの仕事を終えてSuspendThreadする
直前だったりするとResumeしても即Suspendしてしまうので、これを避けるために
クリティカルセクションとフラグが1つ余分に必要になってしまって効率も悪いし
コードもムダに複雑になる。




675 名前:デフォルトの名無しさん mailto:sage [2006/07/26(水) 18:07:51 ]
みなさん、レス有難うございます。

>>674
>autoresetのイベントハンドルを用意して WaitForSingleObject で待たせておき

こんな感じでしょうか?

スレッドB{
while(1){
WaitForSingleObject(XXX);
何か仕事(B*)
}
}

スレッドA{
while(1){
何か仕事の準備(実行中のB*の部分を触らない配慮はしている)
SetEvent(XXX);
}
}

>直前だったりするとResumeしても即Suspendしてしまうので
なんとなく現象の心当たりがあります。



676 名前:デフォルトの名無しさん mailto:sage [2006/07/26(水) 18:21:59 ]
>>675
Bが待機するところはそんな感じです。

あとまぁよく使うパターンとしては
(1) AがBの仕事の完了を待たずににいくつもの仕事を投げておけるようにQueueに仕事を登録して SetEvent する。Bは起こされたら、Queueにある仕事を全て実行してからWaitする。
(2a) 「仕事終わったよイベント(初期値はON)」ってのも用意して、Bが仕事を終えたらSetEventする。Aは仕事終わったよイベントを待ってからBを起こす
(2b) CreateSemaphoreでMaxCount 1 のセマフォを作って、AはWait,→仕事の準備→ReleaseSemaphore、
  BはWait→仕事を取り出して実行→ReleaseSemaphore とする。

仕事が終わったかどうか知りたくなることも多いので、漏れは2aのパターンを多用します。
殆ど等価な 2b でもいいのかも知れない。

677 名前:デフォルトの名無しさん mailto:sage [2006/07/26(水) 19:36:15 ]
>>676
Suspend,Resumeでやってたところを待機オブジェクトにしました。
すっきりした感じがします。
>(2a)
なんとなくこれっぽいことはやっていました。
どうもありがとうございました。

678 名前:デフォルトの名無しさん mailto:sage [2006/07/26(水) 21:47:50 ]
lock-freeについて調べている内に
CAS(CompareAndSwap)という概念にたどりついたのですが
ちょっと教えてください。
/* 関数内の処理はatomicに処理されると仮定*/
bool CAS(void*addr,int expval,int newval){
if(*addr == expval){
*addr = newval;return true;
}
return false;
}
*addr=0;
while(!CAS(addr,0,*addr + 1)){
//※ここでコンテキストスイッチ
}
//アトミックにインクリメント成功?
例えば※の部分で別スレッドがaddrの値を5に変更→0に変更
という動きをした場合、*addr == expvalが成り立ってしまい、
インクリメント成功とみなされてしまう気がするのですが・・・
何か回避策等あるんでしょうか。それとも俺の理解不足なんでしょうか

679 名前:デフォルトの名無しさん mailto:sage [2006/07/26(水) 23:07:03 ]
>>678
「アトミックなインクリメント」というものを理解していないような気がする。
過去に5だったかどうかはさておき、他のスレッドで0にされたものが1に
なるのだから成功している。
というか5で放置されてて6になってもやはり成功。

*addr=0;
IntgerlockedIncrement(&addr); ←APIによるアトミックなインクリメント
などとしたところで、この2行の間に*addrが5になって0になることもある。

「アトミックなインクリメントに失敗」というのは、2つのスレッドで1度ずつ
アトミックなインクリメント操作が行われたにも関わらず2増えないことを言う。
これは正しい実装では決して起きない。

680 名前:デフォルトの名無しさん mailto:sage [2006/07/26(水) 23:07:59 ]
追記:
CASによるアトミックなインクリメントの実装は、正しくは↓

while (!CAS(addr, *addr, *addr+1) {}


681 名前:678 mailto:sage [2006/07/27(木) 21:49:17 ]
>>679
>>680
ありがとうございます。

addr=&val;
while(!CAS(addr,*addr,*addr + 1)){
//※ここでコンテキストスイッチ
}
でも問題が起きそうな気がするんですが・・

とここまで書いて
www-06.ibm.com/jp/developerworks/java/041203/j_j-jtp11234.html
に似たような事が書いてありました
ABA問題というらしいですが

もうちょっと勉強してでなおしてきます・・

682 名前:デフォルトの名無しさん mailto:sage [2006/07/27(木) 23:41:31 ]
とりあえず、CAS(xxx, *addr, *addr+1)
なんて書いている奴は氏んでいいよ。

atomic_inc(int *addr)は
do {
 int var = *addr;
} while (!CAS(addr, var, var+1));
にしないと。

まあ、複数のスレッドで勝手に値をセットするような変数を
特定の個所だけatomic_incを使っても意味は無いがね。

683 名前:デフォルトの名無しさん mailto:sage [2006/07/28(金) 00:03:12 ]
終わった話題についてなにを得意げに語ってるんだろう…。

684 名前:デフォルトの名無しさん mailto:sage [2006/07/28(金) 00:20:12 ]
>>682
それC言語的にやばいやん。



685 名前:デフォルトの名無しさん mailto:sage [2006/07/28(金) 00:31:47 ]
つまり、「ほんと、バカしかいないんだね」ってことか。

686 名前:デフォルトの名無しさん mailto:sage [2006/07/28(金) 00:43:19 ]
やーい
ばかー

687 名前:デフォルトの名無しさん mailto:sage [2006/07/28(金) 07:26:02 ]
volatileですべて解決!

688 名前:デフォルトの名無しさん mailto:sage [2006/07/28(金) 12:24:47 ]
>>682
バカは喪前のほうだと思うが・・・
なぜ自分がバカなのかが知りたかったら、
元のコードの問題点を書いてご覧よ。
書いてるうちにわかるだろ。

689 名前:デフォルトの名無しさん mailto:sage [2006/07/28(金) 17:51:17 ]
元のコードの問題点は関係なくて
*addrを2度読み出して同じ値が取れると思っているのがバカだって事だろ。

690 名前:デフォルトの名無しさん mailto:sage [2006/07/28(金) 17:53:25 ]
しかも、この手のバグは非常に表面化しにくく
再現性が低い(デバッグが難しい)。

691 名前:デフォルトの名無しさん mailto:sage [2006/07/29(土) 15:08:13 ]
volatileですべて解決するという忠告がみえないのか?

692 名前:デフォルトの名無しさん mailto:sage [2006/07/29(土) 16:14:19 ]
別CPUから発言が見えるようになるまでには時間がかかります

693 名前:デフォルトの名無しさん [2006/07/29(土) 18:15:53 ]
VC++とMFCでマルチスレッドなサーバープログラムを書いています。
サーバープログラムを終了する時、ソケットが走ってるスレッドを終了させないといけませんが、
スレッドに終了を通知する手段が分かりません。
どのように終了を通知するのか教えていただけないでしょうか。

よろしくお願いします。

694 名前:デフォルトの名無しさん mailto:sage [2006/07/29(土) 19:01:50 ]
ソケットをどういう風に使ってるかによると思うけど、イベントとか単なるフラグとか。



695 名前:デフォルトの名無しさん mailto:sage [2006/07/29(土) 19:36:20 ]
>>693
ExitProcessで自殺すればおk

696 名前:693 mailto:sage [2006/07/29(土) 19:49:37 ]
CAsyncSocketを継承して作ったUDPのソケットです。
クライアントからやってくるパケットをRecvFromで受けて、データに応じてSendToしているだけです。

現在、スレッドを閉じるのにdeleteでデストラクタを呼び、強制的に終了させているのですが
デバッガで追っかけていくとCAsyncSocketの中でエラーが発生します。
詳細は不明ですがおそらくソケットを閉じずに終了したためではないかと思います。

Win32APIでマルチスレッドなプログラムを組んだときはPostThreadMessageで終了メッセージを
送って、WaitForSingleObjectでスレッドが落ちるのを待っていたのですが、MFCで
そのような手順を踏んだ終了の仕方は(強制終了じゃないやり方)ないのでしょうか?






[ 続きを読む ] / [ 携帯版 ]

前100 次100 最新50 [ このスレをブックマーク! 携帯に送る ] 2chのread.cgiへ
[+板 最近立ったスレ&熱いスレ一覧 : +板 最近立ったスレ/記者別一覧]( ´∀`)<278KB

read.cgi ver5.27 [feat.BBS2 +1.6] / e.0.2 (02/09/03) / eucaly.net products.
担当:undef