Presentation is loading. Please wait.

Presentation is loading. Please wait.

ネットワーク・プログラミング 非同期I/Oとスレッド同期制御.

Similar presentations


Presentation on theme: "ネットワーク・プログラミング 非同期I/Oとスレッド同期制御."— Presentation transcript:

1 ネットワーク・プログラミング 非同期I/Oとスレッド同期制御

2 全体の位置づけ オペレーションシステム(Linux) ソケットプログラミング プロセス カーネルとシステムコール プロセス間通信 スレッド
クライアントーサーバ 非同期I/Oとマルチタスク

3 1.1 サーバーの非同期I/O 非同期I/O シグナルSIGIOの設定 UDPEchoServeの動作
シグナル処理関数がエコー処理をする UDPEchoServer 非同期I/O シグナルSIGIOを使って、パケット受信をプロセスに通知する。 プロセスはシグナルを受信するまで別の処理が出来る。 シグナルSIGIOの設定 sigaction()を使って、シグナルハンドラを指定する。 fcntl()を使って、ソケットのフラグをFASYNC (非同期I/O)に設定する。 UDPEchoServeの動作 SIGIOのシグナルハンドラを設定し、エコー要求があるまで他の処理を行う。 エコー要求が到着するとSIGIOがプロセスに送信され、ハンドラが実行される。 ハンドラは、recvfrom()とsendto()を実行して受信したデータグラムをエコーバックする。 SIGIO handler UDPEchoClient カーネル main signal関数の高機能版 sigaction() Echo SIGIO recvfrom() sendto() Echo Hello SIGIO recvfrom() sendto() Hello

4 1.2 クライアントのタイムアウト処理 タイムアウト タイムアウトの実装 UDPEchoClientの動作 hello hello
1.2 クライアントのタイムアウト処理 タイムアウト パケットの受信がないことを知る方法。 今からT秒後までに受信がなければ、シグナル(SIGALRM)がカーネルからプロセスに送られる。イベントがあれば、シグナルによる通知はリセットされる。 タイムアウトの実装 ブロックする関数(例えば、recvfrom)を実行する前にalarm()を実行する。 unsigned int alarm(unsigned int secs) UDPEchoClientの動作 2秒間応答がないとSIGALRMシグナルが送信されハンドラが起動される。 ハンドラは再送回数を1増やす。 エコーメッセージを再送する。 再送回数が最大値に到達した場合、プログラムを終了する。そうでなければ再送する。 UDPEchoClient UDPEchoServer alarm() sendto() hello hello alarm() sendto() hello 2秒 メッセージ紛失 SIGALRMハンドラ タイムアウト tries++ alarm() sendto() hello メッセージ紛失 タイムアウト SIGALRMハンドラ tries++

5 1.3 UDPEchoClient Timeout.c
#define TIMEOUT_SECS 2 /* タイムアウト秒数*/  … int tries=0; /* 再送回数初期化 */ void CatchAlarm(int ignored); /* SIGALRMハンドラ */ int main(int argc, char *argv[]) { struct sigaction myAction; /* ハンドラ設定に使用する */ /* UDPソケット作成 */ /* alarm シグナルのハンドラの設定 */ myAction.sa_handler = CatchAlarm; /* ハンドラ実行中は他のシグナルをブロックする */ if (sigfillset(&myAction.sa_mask) < 0) DieWithError("sigfillset() failed"); myAction.sa_flags = 0; if (sigaction(SIGALRM, &myAction, 0) < 0) DieWithError("sigaction() failed for SIGALRM"); /* 文字をサーバへ送信 */   … /* 応答待ち */ fromSize = sizeof(fromAddr); alarm(TIMEOUT_SECS); /* タイムアウト設定 */ while ((respStringLen = recvfrom(sock, echoBuffer, ECHOMAX, 0, (struct sockaddr *) &fromAddr, &fromSize)) < 0) if (errno == EINTR) /* アラーム終了 */ { if (tries < MAXTRIES) /* 最大再送回数か? */ printf("timed out, %d more tries...\n", MAXTRIES-tries); if (sendto(sock, echoString, echoStringLen, 0,          (struct sockaddr *)&echoServAddr,           sizeof(echoServAddr)) != echoStringLen) DieWithError("sendto() failed"); alarm(TIMEOUT_SECS); } else DieWithError("No Response"); DieWithError("recvfrom() failed"); /* 正常な受信処理 */ alarm(0); void CatchAlarm(int ignored) /* SIGALRMハンドラ */ tries += 1; タイムアウトが発生 errno.hで定義 された外部変数 タイマーの再セット シグナルSIGALRMのハンドラCatchAlarmを設定 再送回数オーバー タイムアウト 以外で受信失敗 エコー文字の送信 タイマーをリセット タイマーセット 再送回数を1増加

6 セマフォ値が0ならば、セマフォ値が増えるのを待って1減らす
2.スレッド 2.1  セマフォを使った同期制御 スレッド用のセマフォ 使い方はプロセス間通信のセマフォと同じ スレッドの数だけセマフォが必要。 同期の取り方 スレッド1はセマフォ1に1を足し、セマフォ2から1を引く。 スレッド2はセマフォ2に1を足し、セマフォ1から1を引く。 sem_init セマフォの初期化 インクルードファイル   #include <semaphore.h> 書式  int sem_init(sem_t *sem, int pshared, unsigned int value); 戻値 成功時 0 失敗時 -1 sem セマフォ識別子   pshared   0: 現在のプロセス内のスレッド間だけで使用         0以外: 複数プロセス間で使う Value セマフォ値 スレッド1の状態 0: 実行 1: 待ち 1 セマフォ1 セマフォ2 スレッド1 +1 -1 待ち スレッド2 引けない ここから同時に動く sem_post セマフォ値を1増やす インクルードファイル   #include <semaphore.h> 書式  int sem_post(sem_t *sem); 戻値 成功時 0 失敗時 -1   sem_wait セマフォ値を1減らす インクルードファイル   #include <semaphore.h> 書式  int sem_wait(sem_t *sem); 戻値 つねに0を返す スレッド2の状態 0: 実行 1: 待ち セマフォ値が0ならば、セマフォ値が増えるのを待って1減らす

7 2.2 同期を取りながら文字を出力するプログラム
2.2 同期を取りながら文字を出力するプログラム Mainプログラム スレッドで実行する関数 Helloworld.c  その1 helloworld.c その2 char word[]={"Hello World!\n"}; sem_t sem1,sem2; int main() { pthread_t thread1,thread2; void *print1(void *args); void *print2(void *args); sem_init(&sem1,0,0); sem_init(&sem2,0,0); pthread_create(&thread1, NULL, print1, NULL); pthread_create(&thread2, NULL, print2, NULL); pthread_join(thread1,NULL); pthread_join(thread2,NULL); return EXIT_SUCCESS; } void *print1(void *args) { int i; for (i=0; i<strlen(word); i++) { sem_post(&sem1); // sem1 increment sem_wait(&sem2); // sem2 decrement printf("%c",word[i]); fflush(stdout); sleep(1); } return NULL; void *print2(void *args) { sem_post(&sem2); // sem2 increment sem_wait(&sem1); // sem1 decrement 同期ポイント 直ぐに出力 初期化 特別な設定をしなくてもword[]をアクセス出来る!! 同期ポイント soft2]$ gcc helloworld.c -o helloworld -lpthread soft2]$ ./helloworld HHeelllloo WWoorrlldd!!

8 W(7番目の文字)で同期を取るthread1
宿題13 次のインクルードファイルが必要 #include <pthread.h> #include <semaphore.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <unistd.h> (helloworld.cを参考にして)「Hello World!」の「W」で( 「W」以降ではない)同期をとって印字するプログラムhw13.cを作成せよ。但し、二つのスレッドは1秒毎と7秒毎に1文字印字する。 表紙に氏名と学籍番号を書く 本文にプログラムを書く プログラムの実行結果を書く 実施した内容を説明する文章を書く レポートの締切は次の週の水曜日18:00 W(7番目の文字)で同期を取るthread1 void *print1(void *args) { int i; for (i=0; i<strlen(word); i++) { if (i==6) { sem_post(&sem1); // sem1 increment sem_wait(&sem2); // sem2 decrement } printf("%c",word[i]); fflush(stdout); sleep(1); return NULL; thread2では、sleep(7);にする soft2]$ gcc hw13.c -o hw13 -lpthread soft2]$ ./hw13 HHello ello WWorld! orld! soft2]$


Download ppt "ネットワーク・プログラミング 非同期I/Oとスレッド同期制御."

Similar presentations


Ads by Google