マルチスレッド処理 マルチプロセス処理について
DESCRIPTION
マルチスレッド処理 マルチプロセス処理について. CS-B3 ネットワークプログラミング &情報科学科実験 I. このスライドについて. このスライドでは皆さんがプログラムを書いたり,関数を調べたりする過程で行き詰ると予想される部分について簡単に解説します. このスライドの目的は自主学習のサポートであり,説明が簡略化されています.完全な理解には自主学習が必要なので注意してください.. 目次. よくつまずくところ 解決方法の例 解決方法の例 その 1 スレッドの動作 解決方法の例 その 2 プロセスの動作 まとめ. よくつまずくところ. キー入力しなければ - PowerPoint PPT PresentationTRANSCRIPT
マルチスレッド処理マルチプロセス処理について
CS-B3 ネットワークプログラミング &情報科学科実験 I
1
このスライドについてこのスライドでは皆さんがプログラムを書いたり,関数を調べたりする過程で行き詰ると予想される部分について簡単に解説します
このスライドの目的は自主学習のサポートであり,説明が簡略化されています.完全な理解には自主学習が必要なので注意してください.
2
目次よくつまずくところ解決方法の例解決方法の例 その 1スレッドの動作解決方法の例 その 2プロセスの動作まとめ
3
よくつまずくところ
以下のようなプログラムのままになっていませんか?
while(1) {
fgets() でキー入力を取得 ;
send() で入力文字を送信 ;
recv() で相手からメッセージを受け取る ;
}
キー入力しなければ次に進めない
送っている最中はキー入力,受信ができない
受信待ちの間はキー入力,送信ができない
4
解決方法の例
send() も recv() も独立して別々に処理してくれれば楽ですよね?
while(1) { fgets() でキー入力を取得 ; send() で入力文字を送信 ;}
while(1) { recv() する ;}
前処理
後処理
5
send() 用スレッド recv() 用スレッド
解決方法の例 その 1
以下のような実装方法(スレッド)はどうですか?
前処理
後処理
6
スレッドの動作
1 スレッド = 1 関数
•スレッドは指定された関数を 1 つ実行する (main() 関数がもう一個あるような感覚 )
•必要な値は,構造体の中に保存してスレッド用関数に渡せる
•スレッド用関数内で,別の関数を利用することも可能
7
スレッドの作成について
8
pthread.h のヘッダファイルをインクルード
pthread_create 関数でスレッドを作成
pthread を使う際の幾つか注意点・・・ ・終了した子スレッドは pthread_join 関数で解放 ・もしくは pthread_detach 関数でデタッチしておく ・親⇒子の強制終了はデッドロックの可能性がある ・スレッド間通信には排他処理が必要となる などなど
その他 pthread ライブラリ関数についてhttp://d.hatena.ne.jp/gikogeek/20070703やhttp://ja.wikipedia.org/wiki/POSIX%E3%82%B9%E3%83%AC%E3%83%83%E3%83%89などを参照
int main() { /* send 用スレッド作成 */ pthread_create(&SendthreadID, NULL, SendThreadMain, (void *)SendthreadArgs);
/* recv 用スレッド作成 */ pthread_create(&RecvthreadID, NULL, RecvThreadMain, (void *)RecvthreadArgs); 各種処理 ;
return 0;}
/* Send スレッド用関数 */void *SendThreadFunc(void *threadArgs) { 処理 ; return 0;}
/* Recv スレッド用関数 */void *RecvThreadFunc(void *threadArgs) { 処理 ; return 0;}
処理
9
int main() { /* send 用スレッド作成 */ pthread_create(&SendthreadID, NULL, SendThreadMain, (void *)SendthreadArgs);
/* recv 用スレッド作成 */ pthread_create(&RecvthreadID, NULL, RecvThreadMain, (void *)RecvthreadArgs); 各種処理 ;
return 0;}
/* Send スレッド用関数 */void *SendThreadFunc(void *threadArgs) { 処理 ; return 0;}
/* Recv スレッド用関数 */void *RecvThreadFunc(void *threadArgs) { 処理 ; return 0;}
処理
10
SendThreadMain の処理 { 処理 ; return 0;}
新スレッド 1
処理
int main() { /* send 用スレッド作成 */ pthread_create(&SendthreadID, NULL, SendThreadMain, (void *)SendthreadArgs);
/* recv 用スレッド作成 */ pthread_create(&RecvthreadID, NULL, RecvThreadMain, (void *)RecvthreadArgs); 各種処理 ;
return 0;}
/* Send スレッド用関数 */void *SendThreadFunc(void *threadArgs) { 処理 ; return 0;}
/* Recv スレッド用関数 */void *RecvThreadFunc(void *threadArgs) { 処理 ; return 0;}
処理
11
SendThreadMain の処理 { 処理 ; return 0;}
新スレッド 1
処理
int main() { /* send 用スレッド作成 */ pthread_create(&SendthreadID, NULL, SendThreadMain, (void *)SendthreadArgs);
/* recv 用スレッド作成 */ pthread_create(&RecvthreadID, NULL, RecvThreadMain, (void *)RecvthreadArgs); 各種処理 ;
return 0;}
/* Send スレッド用関数 */void *SendThreadFunc(void *threadArgs) { 処理 ; return 0;}
/* Recv スレッド用関数 */void *RecvThreadFunc(void *threadArgs) { 処理 ; return 0;}
処理
12
SendThreadMain の処理 { 処理 ; return 0;}
新スレッド 1
処理
RecvThreadMain の処理 { 処理 ; return 0;}
新スレッド 2
処理
int main() { /* send 用スレッド作成 */ pthread_create(&SendthreadID, NULL, SendThreadMain, (void *)SendthreadArgs);
/* recv 用スレッド作成 */ pthread_create(&RecvthreadID, NULL, RecvThreadMain, (void *)RecvthreadArgs); 各種処理 ;
return 0;}
/* Send スレッド用関数 */void *SendThreadFunc(void *threadArgs) { 処理 ; return 0;}
/* Recv スレッド用関数 */void *RecvThreadFunc(void *threadArgs) { 処理 ; return 0;}
処理
13
SendThreadMain の処理 { 処理 ; return 0;}
新スレッド 1
処理
RecvThreadMain の処理 { 処理 ; return 0;}
新スレッド 2
処理
※ 具体的な実装方法は自主的に調べてみましょう
send() 用プロセス recv() 用プロセス
解決方法の例 その 2
以下のような実装方法(プロセス)はどうですか?
前処理
後処理
14
プロセスの動作
プロセス = プログラムのクローン
•プロセスを作成すると,そのプログラムのコピーが作られる
•コピーされたプログラム(子プロセス)の実行開始位置は,先頭からではなく,元々のプログラム(親プロセス)と同じ続きの位置から
= 親プロセス,子プロセスで以降の処理を分岐させる
•変数の値も子プロセス作成時点のものがコピーされる ( 別領域 )
15
プロセスの作成について
16
fork 関数でスレッドを作成
fork 関数の返り値で自身が親か子を判定できる
fork を使う際の幾つか注意点・・・ ・終了した子プロセスは wait(pid) 関数で解放 ⇒これを怠るとゾンビプロセスが発生する
・各プロセスの変数領域は異なっている ⇒そのままではプロセス間で変数を共有できない ⇒解決策:共有メモリ・パイプなど
などなど
プロセスの動作例えば…
処理
int main() {
/* 子プロセスを作成 */ pid = fork();
if ( 親プロセス ) { 親プロセスの処理 ; }
else if ( 子プロセス ) { 子プロセスの処理 ; } return 0;}
親プロセス
17
プロセスの動作例えば…
int main() {
/* 子プロセスを作成 */ pid = fork();
if ( 親プロセス ) { 親プロセスの処理 ; }
else if ( 子プロセス ) { 子プロセスの処理 ; } return 0;}
親プロセス
処理
int main() {
/* 子プロセスを作成 */ pid = fork();
if ( 親プロセス ) { 親プロセスの処理 ; }
else if ( 子プロセス ) { 子プロセスの処理 ; } return 0;}
子プロセス
処理
18
プロセスの動作例えば…
int main() {
/* 子プロセスを作成 */ pid = fork();
if ( 親プロセス ) { 親プロセスの処理 ; }
else if ( 子プロセス ) { 子プロセスの処理 ; } return 0;}
親プロセス
処理
int main() {
/* 子プロセスを作成 */ pid = fork();
if ( 親プロセス ) { 親プロセスの処理 ; }
else if ( 子プロセス ) { 子プロセスの処理 ; } return 0;}
子プロセス
処理
19
プロセスの動作例えば…
int main() {
/* 子プロセスを作成 */ pid = fork();
if ( 親プロセス ) { 親プロセスの処理 ; }
else if ( 子プロセス ) { 子プロセスの処理 ; } return 0;}
親プロセス
処理
int main() {
/* 子プロセスを作成 */ pid = fork();
if ( 親プロセス ) { 親プロセスの処理 ; }
else if ( 子プロセス ) { 子プロセスの処理 ; } return 0;}
子プロセス
処理
※ 具体的な実装方法の詳細は各自で調べてみましょう20
まとめマルチスレッド処理・マルチプロセス処理によってプログラムを send() 用と recv() 用に分けることで,送受信を並行して行うことができる
プロキシプログラムでは select とマルチスレッド処理・マルチプロセス処理の複数を使うことになるかもしれません
以上の内容をヒントにして,自主学習やプログラムの実装を進めてみてください
このスライドのヒントはあくまでも実装方法の一例です(他の実装方法もあるかもしれません)
21