メインコンテンツまでスキップ

「Multithread」タグの記事が6件件あります

全てのタグを見る

情報処理: 覚え書き

· 約5分
Yu Sasaki
Enterprise Security Manager / Advisor

1. 主なデータの管理・取り出し方法

  1. LIFO (Last-In First-Out): キューなどに使われる。
  2. FIFO (First-In First-Out): スタック。再帰的な処理をする際、実行中の状態を保存しておく為にも使われる。
  3. LFU (Least Frequently Used): 参照頻度が最も少ないものを取り出す。
  4. LRU (Least Recently Used): 未使用時間が最も長いものを取り出す。

C++, pthread: スレッドの同期と排他制御 - MutexとCondition Variable

· 約3分
Yu Sasaki
Enterprise Security Manager / Advisor

以前、Boostライブラリを用いたスレッドの同期と排他制御を取り上げましたが、今記事はそれのpthreadバージョンです(似せただけです)。pthreadライブラリ自体はC言語から扱えますが、今回はstaticなメンバ関数を別スレッドで動かす練習も兼ねてC++で書いてみました。

java.io.StreamCorruptedExceptionが発生した原因とその解決策の一例

· 約3分
Yu Sasaki
Enterprise Security Manager / Advisor

以前というかこの頃Javaで簡単な分散処理サーバ・クライアントシステムのモデルを実装中にこのjava.io.StreamCorruptedExceptionという例外が発生。

StreamCorruptedExceptionの発生原因

結論から言えば、恐らく実行中のスレッドの数がマシンスペックに対して多すぎたのではないかと推定(推定どまり)。 サーバが複数のクライアントを受け付けるので、クライアントのソケット接続(accept時)毎にスレッドを生成する方法を採った。この時はブロッキング型のモデル(この頃ノンブロッキング型は知らなかった)。 例外の発生状況はサーバプログラムをテスト動作時、絶えず約1000クライアントからのリクエストを受け付け、かつレスポンス等を行った場合。なお送受信データはシリアライズされたオブジェクトで、サイズは平均5KB。その時テストマシンで走らせたスレッド数が約5000。 シリアライズの復元の問題かと考えたが、送受信するオブジェクトのクラスとそのserialVersionUIDは揃えており、500クライアント位ではこれといった異常なく動作していた。 実際にある時間のクライアントの送信データ数とサーバの受信データ数を確認してみたら、両数値の差が生じていて、約200リクエストがソケット部分で溜まったところでダウンしました。 スレッド数が多いと、その分スレッドの切り替えが頻発したり、待たされるスレッドが出てくる。その為、ソケットの部分で受信データが許容量以上に溜まって、I/Oのどこかがオバーフローか変になった可能性もある。

例外発生時のスタックトレースの一部抜粋

java.io.StreamCorruptedException: unexpected reset; recursion depth: 1
at java.io.ObjectInputStream.handleReset(Unknown Source)
at java.io.ObjectInputStream.readObject0(Unknown Source)
at java.io.ObjectInputStream.skipCustomData(Unknown Source)
at java.io.ObjectInputStream.readNonProxyDesc(Unknown Source)
at java.io.ObjectInputStream.readClassDesc(Unknown Source)
at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.io.ObjectInputStream.readObject0(Unknown Source)
at java.io.ObjectInputStream.readObject(Unknown Source)

また、これ以外にOptionalDataExceptionという例外も併発しましたが、これも同じ原因かと推定。

java.io.OptionalDataException
at java.io.ObjectInputStream.readObject0(Unknown Source)
at java.io.ObjectInputStream.readObject(Unknown Source)

試した解決策

スレッド数を抑える

これは解決策とは言えないが、マシンスペック(CPU[コア]数やクロックなど)に対してスレッド数が多すぎるのが問題だと推定したので、ある程度スレッド数を抑えて運用したところ例外は発生しなくなった。

もう一度接続しなおす

例外をtry-catchブロックでキャッチできるので、それに合わせて接続しなおしてリクエストorレスポンスを再送することで一時対処した。

ノンブロッキング型にする

nio(New I/O)ライブラリが用意されているので、それを用いたノンブロッキング型の機構にして、スレッドプールを用意することでスレッド数やコンテキストスイッチ、オーバヘッドをある程度抑えることが可能と考えるが、まだ未検証。 どちらにせよ、根本原因の究明にはkernel dump等の情報を取って解析していく必要がある。。。

C++, boost::thread : スレッドの同期と排他制御 - mutex、conditionクラス

· 約5分
Yu Sasaki
Enterprise Security Manager / Advisor

複数のスレッドから1つの変数にアクセスする際、システム側のスレッドスケジューリング次第で、予期せぬ書き換えが起こってしまう場合があります。その為、ある1つのスレッドが変数にアクセスしている際は他のスレッドをブロックする排他制御やスレッドの同期を行う必要があります。C++でJavaのsynchronizedメソッド/ブロックと同じような記法でクリティカルセクションを実装する方法の1つにboost::threadライブラリのmutexとconditionクラスがあります。

C++, boost::thread : スレッドグループの生成と実行

· 約2分
Yu Sasaki
Enterprise Security Manager / Advisor

同じような処理を行うスレッドが複数ある場合は、それらをスレッドグループでまとめると、スレッドへの操作がやり易くなります。スレッドグループへの登録には、boost::thread ライブラリの thread_group クラスを用いて、メンバ関数 create_thread() の引数にマルチスレッドで実行したい関数のアドレスを指定します。

それでは下記のサンプルで実際にその過程と実行結果を確認してみましょう。

C++, boost::thread : スレッドの生成と実行

· 約5分
Yu Sasaki
Enterprise Security Manager / Advisor

C/C++でスレッドを扱う場合は、プラットフォームによって使用するライブラリが違います。 Windows なら Windows API の thread で、 UNIX や Linux 系ならば pthread ライブラリ等を使用します。プラットフォーム依存するコードは可搬性に難があり、解決策の1つとしてプリコンパイルで依存部分をプラットフォームに合わせたライブラリを選択してコンパイルする方法があります。