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

このエントリーをはてなブックマークに追加
627デフォルトの名無しさん
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デフォルトの名無しさん:2006/07/18(火) 19:32:26
わざわざageんなよ
630デフォルトの名無しさん:2006/07/18(火) 22:10:43
コンパイル・リンク時のコマンドライン見せろ
631デフォルトの名無しさん:2006/07/19(水) 01:14:42
>>627
> accept() の前後に pthread_mutex_lock(), pthread_mutex_unlock() で
> ロック、アンロックをしても同じでした。

この時点でプログラミングの問題じゃないことに気付け。
632デフォルトの名無しさん:2006/07/19(水) 01:56:34
>>627
>これって Linux のバグなんでしょうか?
つかその前に、どこで習ったんだそんな阿呆な手順。
633デフォルトの名無しさん:2006/07/19(水) 02:07:07
acceptしてからthreadおこせ
634デフォルトの名無しさん:2006/07/19(水) 03:17:38
>>627
よく知らんけど、下記のApache のディレクティブの存在なんかを見ると
accept は直列化 (同時に1つのプロセス・スレッドからのみ呼ぶ)するのが
普通なんじゃないかと思うが・・・

http://httpd.apache.org/docs/2.2/ja/mod/mpm_common.html
635デフォルトの名無しさん: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デフォルトの名無しさん:2006/07/19(水) 11:14:26
>>636
そこが疑問ですよ。なんで既に取得してオープンされているファイル
ディスクリプタと同じ値のファイルディスクリプタが返って来るのか
という点がね。

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

で、その後、accept() を一つのスレッドでだけやって、他のスレッドは
待機させておいて、accept() 成功後にファイルディスクリプタを待機
スレッドに渡すように作り替えたらちゃんと動くプログラムは作れました。
理由はどうあれこういう風にするか、あるいは accept() 成功後にスレッド
作るように書かないと駄目なようですね。
638デフォルトの名無しさん:2006/07/19(水) 11:25:03
>>627
> int cs = accept(...); // ここで cs が別スレッドと同じ値になる。
本当にこれと同じ書き方だったんだな?
csが大域変数だったってオチがありそうだ。
639デフォルトの名無しさん:2006/07/19(水) 11:30:07
>>638
いいえ。大域ではありません。autoです。
640デフォルトの名無しさん:2006/07/19(水) 12:26:13
生半可な学習しないで、ファイルディスクリプタについてちゃんと勉強したら?
641デフォルトの名無しさん:2006/07/19(水) 13:35:02
>>637
>スレッドは clone() システムコールで作った
ちょwwwwおまwwwww帰れwwwww
642デフォルトの名無しさん:2006/07/19(水) 13:56:58
げ、pthread_createで作ってんじゃないのか・・・!!!
643デフォルトの名無しさん:2006/07/19(水) 14:24:08
>>640
生半可? どの辺がですか?

>>641-642
pthread_create() で作ってますよ。clone() は内部動作の話です。
644デフォルトの名無しさん:2006/07/19(水) 14:29:47
こいつむかつく〜☆
645デフォルトの名無しさん:2006/07/19(水) 14:36:37
>>643
コンパイルオプションとかはどうだろう・・・ -pthread とか付け忘れありませんか?
646デフォルトの名無しさん:2006/07/19(水) 14:42:25
647デフォルトの名無しさん:2006/07/19(水) 14:48:29
>>643
続きは以下で。
ネットワークプログラミング相談室 Port17
http://pc8.2ch.net/test/read.cgi/tech/1148944560/
648デフォルトの名無しさん:2006/07/19(水) 14:59:44
>>646
-lpthread だけ指定して -pthread を指定していないのではないか、といっているのだが。
649デフォルトの名無しさん:2006/07/19(水) 15:38:16
>>648
-pthread は指定していませんでしたが、man ページや info 見ると
Linux では関係ないようですよ。

念のため指定してテストしてみましたが、同じ動作になりました。
650デフォルトの名無しさん:2006/07/19(水) 15:45:45
いい加減、誰かファイルディスクリプタの説明してやれよw
651デフォルトの名無しさん:2006/07/19(水) 15:47:52
>>647
そっちの方がいいですか?
スレッドとネットワークと Linux が混ざった疑問なのでどこがいいのか迷ったんですが。
652デフォルトの名無しさん:2006/07/19(水) 16:00:17
>>640>>650
pthread_createで作ったスレッド間では、ファイルディスクプリタは共有されます。
すなわち、同じ数値=同じソケット端点。
何がいいたのか知らんがこれでいいか?
653デフォルトの名無しさん:2006/07/19(水) 16:06:07
>>651
どっちがいいのかはわからんけど、このスレじゃ解決できなさそうじゃん。
654デフォルトの名無しさん:2006/07/19(水) 16:20:45
Linuxのスレッドが特別なプロセスだったのは、2.4より前の話だよ。
# 例えばpidやsignalの扱いなど。
>>627は、2.6.17だから関係ない。
655デフォルトの名無しさん:2006/07/19(水) 16:21:59
>>637
> accept() 成功後にスレッド作るように書かないと駄目なようですね。

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

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

>>653
今のところそんな感じしますね。
657デフォルトの名無しさん:2006/07/19(水) 16:24:17
>>654-655
そうですか…。じゃあ何でだろう?
658デフォルトの名無しさん:2006/07/19(水) 16:26:01
こっちの方がいいかも。
UNIX板 pthread地獄
http://pc8.2ch.net/test/read.cgi/unix/1010933537/
読んでる人はこの板と重複がかなりあるかもだけど。
659デフォルトの名無しさん:2006/07/19(水) 16:34:42
>>658
そこはたしかに近いこと話し合われてたスレですね。
じゃあそこに移転します。

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