質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
スレッドセーフ

マルチスレッド環境において、複数のスレッド上で常に正常に実行する事が可能なコードを、スレッドセーフなコードと呼びます。

サーバ

サーバは、 クライアントサーバモデルにおいてクライアントからの要求に対し 何らかのサービスを提供するプログラムを指す言葉です。 また、サーバーソフトウェアを稼動させているコンピュータ機器そのもののことも、 サーバーと呼ぶ場合もあります。

Q&A

解決済

1回答

1467閲覧

サーバーのスレッドについて

sachito

総合スコア13

スレッドセーフ

マルチスレッド環境において、複数のスレッド上で常に正常に実行する事が可能なコードを、スレッドセーフなコードと呼びます。

サーバ

サーバは、 クライアントサーバモデルにおいてクライアントからの要求に対し 何らかのサービスを提供するプログラムを指す言葉です。 また、サーバーソフトウェアを稼動させているコンピュータ機器そのもののことも、 サーバーと呼ぶ場合もあります。

0グッド

2クリップ

投稿2018/02/08 11:59

マルチスレッドのサーバーでは、まずはリクエストを受け付けてディスパッチするスレッドがあると考えていますが、
リクエストが来るまで、このディスパッチスレッドはどういう状態になっていますか?

なぜスレッドが終了しないのか不思議です。

初歩的かもしれませんがよろしくお願いします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

リクエストが来るまで、このディスパッチスレッドはどういう状態

クライアントからの接続要求(あるいはパケットの到来)をずっと待っている状態(スレッドがブロックされた状態)です。

「ずっと待つ」ためにはOSや言語ライブラリーにそういう機能があるのでそれを用います。例えばUnix系OSであればlistenシステムコールがそれにあたります。これは入出力用のシステムコールの一つですが、他の同期的な入出力機能と同様、興味のある状態変化(クライアントからの接続要求)が発生するまでは呼び出し元スレッドをブロックします。

サーバー計算機上にあるサーバーの実体は単なる一つのプログラムであり、それは例えば次のような雰囲気の無限ループでできています。つまり「もういいから止まりなさい」と言われるまでずっと同じことをやり続けています。

while (true) { // 新たな接続が到来するまで待つ listen(...); // その接続用の通信用リソース(ソケットを示すファイル記述子だったりする)を確保する client_socket = accept(...); // 接続を受け付けたクライアントに対するスレッドを決め(生成したり既存のものを割り当てたり) client_thread = create_or_select_client_thread(); // そこへclient_socketに対する仕事を「やっといてね」と移譲する。 dispatch_request(client_thread, client_socket); // 自分自身は次の接続待ちに入る }

(上のコードに出てきている関数名などは便宜上のものであり、現実に存在する特定のOS/言語/ライブラリーでそのまま動作するような実例ではありません)

なぜスレッドが終了しないか

先に述べた例にあるように、繰り返し同じことをずっとやり続けているからです。


この質問が出るということは「スレッドのブロック」のイメージが曖昧なのかな・・・という気もしました。もしそうなら別途「スレッドのブロックとは何か?」を質問してみてもよいかも知れません。

投稿2018/02/08 13:10

KSwordOfHaste

総合スコア18394

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sachito

2018/02/08 14:57

>KSwordOfHasteさん 丁寧なご説明に感謝します。 スレッドがブロックされている状態、とのことですが、 whileループを実行し続けているのならば、ブロックされているとは言わないのでは? と感じました。 私は、あるスレッドがブロックされていることを、完全に処理が止まっていることと認識しています。 おっしゃっているように「スレッドのブロック」のイメージが曖昧で勘違いしているのでしょうか?
KSwordOfHaste

2018/02/08 16:25 編集

例えば for (;;) i++; このコードは無限ループですがスレッドはブロックしません。大雑把に言えば常にCPUを使い続け動き続けます。それに対して for (;;) read(fd, buffer, sizeof(buffer)); のようなものは同じ無限ループですが(これまた大雑把に言えば)CPUを殆ど使いません。readしようとする入出力データの準備ができるまではスレッドはCPUを使わずブロック状態になります。このスレッドは入出力処理を継続中(機能としては何かをやっている途中)なのでそのことを「処理が止まっている」とは普通表現しないと思います。 --- 追記:うーん、「普通表現しないと思う」と書きましたが、それは言い過ぎでした。忘れてください。単に「CPUは使ってなくて、処理が保留状態だけどあくまでスレッドは終了していない」とでもいった方がよいと思います。
sachito

2018/02/09 01:24

コメントありがとうございます。 つまり最初のサンプルコードでいうと、 1回目のループでlistenした時に、システムコールの中で接続が来るまでスレッドがブロックされていて、 接続が来たら処理が再開されて2回目のループに入る、という流れでしょうか? 私はJavaで想像しています。 Javaコードで「接続が来たら処理を開始する」という処理を書いているイメージでしたが、それはOS任せといった感じでしょうか?
KSwordOfHaste

2018/02/09 01:58

> 接続が来るまでスレッドがブロックされていて、接続が来たら処理が再開 おっしゃる通りです。 > Javaコードで「接続が来たら処理を開始する」という処理を書いている なるほど、質問者さんの疑問がなんとなくわかった気がします。JavaのServletのようなものをイメージしておられるのではないでしょうか。実はlisten的なことやaccept的なことはどんなサーバーでも同じようなものなのでそれはフレームワークが内部的にやってくれてます。つまり自分の回答にある「接続を待っている」のはフレームワーク内のコードで全て実現されており、回答コードにあるdispatch_requestの中でServletのインスタンス生成とdoGetなどのメソッドの起動まで全て面倒を見てくれるわけです。アプリケーションプログラマーはフレームワークから呼び出してもらうdoGetの実装だけ気にすればよいといった感じですね。しかしそれでもプログラム全体の動きとしては回答にあるとおり「接続が到来するのをずっと待っている」はずです。実際Javaでもフレームワークを使わずに自前でサーバーを書くと自分の回答のような雰囲気で書けるのです。だれもそんな低水準なことを一々書きたくないからフレームワークを使っているだけで「接続を待つためにサーバーの特定のスレッドがブロック状態になる」点は本質的に同じだと思ってよいでしょう。
sachito

2018/02/09 02:32

ありがとうございます。 > JavaのServletのようなものをイメージ はい。webコンテナにtomcatを使っているのですが、どうやってリクエストを受け取ってサーブレットを起動しているのかなという疑問から質問にいたりました。 ご教授頂いたこと内容から、 tomcatデーモンプロセスにディスパッチスレッドがあって、ずっとlistenしている。 ↓ webサーバーからtomcatプロセスにリクエストが投げられる。 ↓ ディスパッチスレッドがacceptして新スレッドでサーブレットを起動する という理解でいったん落ち着きました。 ※こちらの理解が間違っていたら指摘お願いします。 listenの仕組み(ソケット・バックログ?)や、 tomcatがサーブレットを起動するときスレッドをどうやって使うのか?(スレッドプール・キュー?) というところを、また調べてみたいと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問