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 ておきます。よろしくお願いします。
わざわざageんなよ
コンパイル・リンク時のコマンドライン見せろ
>>627 > accept() の前後に pthread_mutex_lock(), pthread_mutex_unlock() で
> ロック、アンロックをしても同じでした。
この時点でプログラミングの問題じゃないことに気付け。
>>627 >これって Linux のバグなんでしょうか?
つかその前に、どこで習ったんだそんな阿呆な手順。
acceptしてからthreadおこせ
>>630 gcc hoge.c -lpthread
>>631 どういう意味ですか? 同時に複数のスレッドが accept() しないように
しただけですが?
>>632 これは阿呆な手段ですか? 何故? その辺詳しく教えてもらえますか?
どこで習ったかは記憶にありません。ただ昔 Java で似たようなものを
作った時はちゃんと動いたと思いました。
>>633 それはつまり accept() は親(?)スレッド一つでやるということですね。
636 :
デフォルトの名無しさん:2006/07/19(水) 10:02:36
accept()を排他しても、
そのプログラムがまともにうごかん事に疑問はないのか?
他の部分がおかしいだけではないのか?
>>636 そこが疑問ですよ。なんで既に取得してオープンされているファイル
ディスクリプタと同じ値のファイルディスクリプタが返って来るのか
という点がね。
気になるのは Linux の場合スレッドは clone() システムコールで作った
特殊な別プロセスであるということです。別プロセスだから複数スレッドで
accept() した時に同一ファイルディスクリプタが取れてしまうんじゃない
かな、とは思ったんですが、確証がなかったので質問したんです。
(Linux板の方で質問した方がよかったかな? でも他のOSではこういうのは
できないのかも少し気になる)。
で、その後、accept() を一つのスレッドでだけやって、他のスレッドは
待機させておいて、accept() 成功後にファイルディスクリプタを待機
スレッドに渡すように作り替えたらちゃんと動くプログラムは作れました。
理由はどうあれこういう風にするか、あるいは accept() 成功後にスレッド
作るように書かないと駄目なようですね。
>>627 > int cs = accept(...); // ここで cs が別スレッドと同じ値になる。
本当にこれと同じ書き方だったんだな?
csが大域変数だったってオチがありそうだ。
>>638 いいえ。大域ではありません。autoです。
生半可な学習しないで、ファイルディスクリプタについてちゃんと勉強したら?
>>637 >スレッドは clone() システムコールで作った
ちょwwwwおまwwwww帰れwwwww
げ、pthread_createで作ってんじゃないのか・・・!!!
>>640 生半可? どの辺がですか?
>>641-642 pthread_create() で作ってますよ。clone() は内部動作の話です。
こいつむかつく〜☆
>>643 コンパイルオプションとかはどうだろう・・・ -pthread とか付け忘れありませんか?
>>646 -lpthread だけ指定して -pthread を指定していないのではないか、といっているのだが。
>>648 -pthread は指定していませんでしたが、man ページや info 見ると
Linux では関係ないようですよ。
念のため指定してテストしてみましたが、同じ動作になりました。
いい加減、誰かファイルディスクリプタの説明してやれよw
>>647 そっちの方がいいですか?
スレッドとネットワークと Linux が混ざった疑問なのでどこがいいのか迷ったんですが。
>>640>>650 pthread_createで作ったスレッド間では、ファイルディスクプリタは共有されます。
すなわち、同じ数値=同じソケット端点。
何がいいたのか知らんがこれでいいか?
>>651 どっちがいいのかはわからんけど、このスレじゃ解決できなさそうじゃん。
Linuxのスレッドが特別なプロセスだったのは、2.4より前の話だよ。
# 例えばpidやsignalの扱いなど。
>>627は、2.6.17だから関係ない。
>>637 > accept() 成功後にスレッド作るように書かないと駄目なようですね。
そんなことはない。
>>652 それは知ってますよ。だからこそOSがおかしいんじゃないかと思ったんですから。
元々の質問を要約すると、まだ close() されていないファイル
ディスクリプタの値を accept() が返して来るのは何故かです。
一つのスレッドが accept() で 5 を受け取ったとして、それが
close() される前にもう一つのスレッドが行った accept() が
受け取ったファイルディスクリプタの値も 5 だったということです。
これ、accept() を一つのスレッドでしかやらなければ当然 6 などの
違う値が返って来ます。
>>653 今のところそんな感じしますね。
>>658 そこはたしかに近いこと話し合われてたスレですね。
じゃあそこに移転します。
こちらのスレのみなさまありがとうございました。