Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
パイプラインによるプロセス間通信を理解する
Search
Kotaro Kamashima
October 30, 2022
Programming
0
380
パイプラインによるプロセス間通信を理解する
社内向け勉強会に用意した資料「パイプラインによるプロセス間通信を理解する」です。
Kotaro Kamashima
October 30, 2022
Tweet
Share
More Decks by Kotaro Kamashima
See All by Kotaro Kamashima
Navigation Bar と権限管理
kotaro666
0
16
Flutter Redux の内部構造を考える
kotaro666
0
280
Other Decks in Programming
See All in Programming
ペアーズでの、Langfuseを中心とした評価ドリブンなリリースサイクルのご紹介
fukubaka0825
2
320
Domain-Driven Transformation
hschwentner
2
1.9k
Amazon Bedrock Multi Agentsを試してきた
tm2
1
280
プログラミング言語学習のススメ / why-do-i-learn-programming-language
yashi8484
0
130
富山発の個人開発サービスで日本中の学校の業務を改善した話
krpk1900
4
380
第3回関東Kaggler会_AtCoderはKaggleの役に立つ
chettub
3
1k
Introduction to kotlinx.rpc
arawn
0
690
『GO』アプリ データ基盤のログ収集システムコスト削減
mot_techtalk
0
120
CI改善もDatadogとともに
taumu
0
110
GitHub Actions × RAGでコードレビューの検証の結果
sho_000
0
260
[JAWS-UG横浜 #79] re:Invent 2024 の DB アップデートは Multi-Region!
maroon1st
1
140
『品質』という言葉が嫌いな理由
korimu
0
160
Featured
See All Featured
Why You Should Never Use an ORM
jnunemaker
PRO
55
9.2k
10 Git Anti Patterns You Should be Aware of
lemiorhan
PRO
656
59k
Navigating Team Friction
lara
183
15k
Improving Core Web Vitals using Speculation Rules API
sergeychernyshev
9
440
What’s in a name? Adding method to the madness
productmarketing
PRO
22
3.3k
Embracing the Ebb and Flow
colly
84
4.6k
Adopting Sorbet at Scale
ufuk
74
9.2k
What's in a price? How to price your products and services
michaelherold
244
12k
How GitHub (no longer) Works
holman
314
140k
Done Done
chrislema
182
16k
Fireside Chat
paigeccino
34
3.2k
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
28
9.3k
Transcript
© Nzigen, Inc. パイプラインによるプロセス間通信を理解する 釜島 光太郎
本日のアジェンダ
本日のアジェンダ 1. ゴール 2. 前提知識 a. ファイルディスクリプタとは? b. 標準入出力と標準エラー出力とは?
c. パイプライン実行時のデータの流れを概略 d. forkを使って子プロセスを作る 3. パイプラインを使ったプロセス間通信 a. 子プロセスの処理 b. 親プロセスの処理
ゴール
ゴール パイプラインを伴ったコマンドを実行するとき、内部ではどのような動作が行われているのかを理解する $ cat access.log | grep “TARGET”
前提知識
前提知識 1. ファイルディスクリプタとは? 2. 標準入出力と標準エラー出力とは? 3. パイプライン使用時のデータの流れ 4. forkを使って子プロセスを作る
前提知識 ファイルディスクリプタ
ファイルディスクリプタ • プログラムがファイル等の外部のリソースにアクセスし たり、アクセスされたりする際に使われる抽象的な概 念 • UNIX/Linux系では、このファイルディスクリプタがファイル だけでなく、ソケットやパイプラインにも使われている
• この抽象的なファイルディスクリプタを使って、ファイルの 中身を見たり、ファイルに書き込んだりする • ファイルディスクリプタは小さい整数値から割り当てられる • OS標準規格では、0~2がすでに使用されているため、通 常は3から順番に割り当てられる • プログラム内で使用できるファイルディスクリプタの上限が 決まっている #define FILE_NAME "infile.txt" int main(void) { int fd; fd = open(FILE_NAME, O_RDONLY); // 読み込み専用でファイルを開く if (fd == -1) // ファイルを開くのに失敗した場合 { // エラー対応 } printf("File Descriptor = %d\n", fd); return (0); } bash-3.2$ ls Makefile ex00 infile.txt main.c bash-3.2$ ./ex00 File Descriptor = 3 サンプルプログラムはこちら
ファイルディスクリプタ • ulimit -n を使って、使用できるファイルディスクリプタ の上限を確認できる • 第2引数に整数値を渡すことで、現在のプロセス内の ファイルディスクリプタ上限値を変更できる
• 左の例は、ファイルディスクリプタの上限値を3に変更 したため、プログラム内でファイルを開けないエラーが 発生している bash-3.2$ ulimit -n 256 bash-3.2$ ulimit -n 3 bash-3.2$ ./ex00 open: Too many open files
前提知識 標準入出力と標準エラー出力
標準入出力と標準エラー出力 標準入力(stdin) ファイルディスクリプタ : 0 標準出力(stdout) ファイルディスクリプタ : 1
標準エラー出力(stderr) ファイルディスクリプタ : 2
標準入出力と標準エラー出力 1. プログラムが起動する 2. 無限ループ状態にする 3. 標準入力を待つ 4. 標準入力データを読み込む
5. 読み込んだデータを標準出力する 6. 2 に戻る
標準入出力と標準エラー出力 #define MAX_BYTES 100 // 最大読み込みバイト数の定義 int main(void) //
① プログラムが起動する { ssize_t bytes; // 読み込み成功した分のバイト数を格納する変数 char buffer[MAX_BYTES + 1]; // 読み込んだデータを格納する静的配列 while (1) // ② 無限ループ状態にする { // ③,④ 標準入力からデータを読み取り、バッファに格納する。 bytes = read(STDIN_FILENO, &buffer, MAX_BYTES); if (bytes == -1) // 読み込み失敗時の対応 { // エラーメッセージとともに標準エラー出力する } buffer[bytes] = '\0'; // 終端文字列としてヌル文字を代入する write(STDOUT_FILENO, buffer, bytes); // ⑤ バッファに格納されたデータを標準出力する bzero(buffer, bytes); // バッファの中を初期化する } return (0); } cat を使った標準入出力と標準エラー出力例 1. プログラムが起動する 2. 無限ループ状態にする 3. 標準入力を待つ 4. 標準入力データを読み込む 5. 読み込んだデータを標準出力する 6. 2 に戻る サンプルプログラムはこちら
前提知識 パイプライン使用時のデータの流れ
パイプライン実行時のデータの流れを概略 $ cat access.log | grep “TARGET” どういう処理が実行されるかイメージできますか?
パイプライン実行時のデータの流れを概略 $ cat access.log | grep “TARGET” ① ②
③ ④ ⑤ 1. ファイルを開いて、中身を読み込む 2. 読み込んだ内容をパイプラインを通じて、次のプログラム(プロセス)に渡す 3. パイプラインを通じて、流れてきたデータを読み込む 4. 渡された引数を検索文字列として、読み込んだデータを抽出する 5. 抽出したデータを標準出力する
パイプライン実行時のデータの流れを概略 $ cat access.log | grep “POST” を実行した時の例
前提知識 forkを使ったプロセス生成
forkを使ったプロセス生成 プロセスとは? • OS上で動いているプログラムまたはタスクのこと ◦ 皆さんが日常で使用しているChromeやGoogleChatアプリ、Gatheアプリも独立したプロセスとして動いている
◦ Linuxコマンドも一つひとつが独立したプロセスで実行されている ◦ 現在実行されているプロセスは、psコマンドやtopコマンドで確認できる • 各プロセスは独立して動いている ◦ 各プロセスは独立したメモリの中で動いている ◦ 独立して動いているので、一つのプロセスに致命的なバグが発生して緊急停止しても、他のプロセスには害を与えない • 実行されるプログラムを親として、forkを実行すると子プロセスが作られる ◦ 子プロセスは親プロセスの複製で作られる(fork) ◦ 親プロセスは子プロセスの状態を監視することができる • プロセス間でのデータのやり取りは大変だが、やる方法は何個かある ◦ シグナル通信 ◦ ソケット通信 ◦ セマフォ(プロセス間の排他制御) ◦ パイプライン(親子プロセス間で行う通信) → 今回のテーマ
forkを使ったプロセス生成 とある平日、親太郎が自宅でリモートワークをしていました。 そこに、子太郎が部屋に入ってきて、「お父さん遊ぼう!」と言いました。親太郎はまだ仕事中です。 そこで、マインクラフトでお城を作る(所要時間:3時間)ように子太郎に促し、その間自分は仕事をするようにしました。 そして、親太郎は仕事をしつつ、子供の遊びが終わるのを待ちます。子供の遊びが終わり、ちょうど仕事も終わったので、その後一緒にご飯を 食べに行きました
fork wait 遊び 仕事
forkを使ったプロセス生成 apache の例 子プロセス 子プロセス 子プロセス 子プロセス 子プロセス prefork
C10k問題
forkを使ったプロセス生成 int main(void) { pid_t pid; int status; printf("1.
Execute fork.\n"); pid = fork(); if (pid == -1) { // エラー処理 } else if (pid == 0) // 子プロセスの処理 { printf("2. Executing child process....\n"); sleep(2); printf("3. Finishing child process!\n"); exit(0); // 子プロセスを終了し、親に SIGCHILDシグナルが送信される } else // 親プロセスの処理 { wait(&status); // 子プロセスが終了するまで呼び出し側をブロックする printf("4. Executing parent process....\n"); } printf("5. Finishing program.\n"); return (0); } サンプルプログラムはこちら
パイプラインを使った プロセス間通信
パイプラインを使ったプロセス間通信 Q. プロセス間でデータを渡すためにどうするか? A. 糸電話のようにプロセス間にデータを橋渡しするものを作ってあげる
パイプラインを使ったプロセス間通信 int main(void) { int pipe_fd[2]; // 生成されたパイプラインの読み込み口と書き込み口のファイルディスクリプタが 格納される静的配列
pid_t pid; int status; pipe(pipe_fd); // パイプラインを作る return (0); } プロセス 0 1 2 pipe_fd[0] 3 4 pipe_fd[1] 標準エラー 標準出力 標準入力 書き込み 読み出し
パイプラインを使ったプロセス間通信 # define PIPE_READ_FD 0 # define PIPE_WRITE_FD 1
# define MAX_BYTES 100 int main(void) { int pipe_fd[2]; char buffer[MAX_BYTES + 1]; ssize_t bytes; pipe(pipe_fd); // パイプラインを生成する write(pipe_fd[PIPE_WRITE_FD], "This is test message.", 21); // パイプライン書き込み口に出力する bytes = read(pipe_fd[PIPE_READ_FD], &buffer, MAX_BYTES); // パイプライン書き込み口から読み込む if (bytes == -1) // 読み込み失敗時 { // エラー対応 } buffer[bytes] = '\0'; write(STDOUT_FILENO, buffer, bytes); // 読み込んだデータを標準出力する return (0); } プロセス 0 1 2 pipe_fd[0] 3 4 pipe_fd[1] 標準エラー 標準出力 標準入力 書き込み 読み出し サンプルプログラムはこちら
パイプラインを使ったプロセス間通信 子プロセス 0 1 2 3 4 標準入力 標準出力
標準エラー pipe_fd[0] pipe_fd[1] 親プロセス 0 1 2 3 4 標準入力 標準出力 標準エラー pipe_fd[0] pipe_fd[1] 書き出し 読み出し 書き出し 読み出し パイプライン pipeしてから、fork実行後の様子。この状態では、ちゃんとデータが期待通りに流れない。
パイプラインを使ったプロセス間通信 子プロセス 0 1 2 3 4 標準入力 標準出力
標準エラー pipe_fd[0] pipe_fd[1] 親プロセス 0 1 2 3 4 標準入力 標準出力 標準エラー pipe_fd[0] pipe_fd[1] 書き出し 読み出し 書き出し 読み出し パイプライン パイプライン内で出入り口を操作することで、データの通り道を決めてあげる
パイプラインを使ったプロセス間通信 int main(void) { int pipe_fd[2]; pid_t pid; int
status; pipe(pipe_fd); pid = fork(); if (pid == -1) // エラー対応 { // エラー対応 } else if (pid == 0) // 子プロセス { start_child_process(pipe_fd); } else // 親プロセス { wait(&status); // 子プロセスを待つ start_parent_process(pipe_fd); } return (0); } • main 関数の大まかな実装 • forkして子プロセスを作る • 子プロセス内で前半の処理 (cat access.log)を行う • 親プロセス内で後半の処理 (grep “TARGET”)を行う サンプルプログラムはこちら
子プロセスの処理
パイプラインを使ったプロセス間通信 int main(void) { int pipe_fd[2]; pid_t pid; int
status; pipe(pipe_fd); pid = fork(); if (pid == -1) // エラー対応 { // エラー対応 } else if (pid == 0) // 子プロセス { start_child_process(pipe_fd); } else // 親プロセス { wait(&status); // 子プロセスを待つ start_parent_process(pipe_fd); } return (0); } static void start_child_process(int *pipe_fd) { int file_fd; close(pipe_fd[PIPE_READ_FD]); // パイプライン読み込み口を閉じる file_fd = open("access.log", O_RDONLY); // access.logファイルを開く if (file_fd == -1) { perror("open"); exit(1); } dup2(file_fd, STDIN_FILENO) // 標準入力を access.logファイルFDのコピーとして作 成する close(file_fd); // access.logファイルFDを閉じる dup2(pipe_fd[PIPE_WRITE_FD], STDOUT_FILENO) // 標準出力をパイプライン書き 込み口のコピーとして作成する close(pipe_fd[PIPE_WRITE_FD]); // パイプライン書き込み口を閉じる execute_child_command(); // 子プロセスの処理を実行する exit(0); // 子プロセスを終了し、親に SIGCHILDが送信される }
パイプラインを使ったプロセス間通信 static void start_child_process(int *pipe_fd) { int file_fd; close(pipe_fd[PIPE_READ_FD]);
// パイプライン読み込み口を閉じる file_fd = open("access.log", O_RDONLY); // access.logファイルを開く if (file_fd == -1) { // エラー処理 } dup2(file_fd, STDIN_FILENO) // 標準入力をaccess.logファイルFDのコピーとして作成する close(file_fd); // access.logファイルFDを閉じる dup2(pipe_fd[PIPE_WRITE_FD], STDOUT_FILENO) // 標準出力をパイプライン書き込み口のコピーとして作成する close(pipe_fd[PIPE_WRITE_FD]); // パイプライン書き込み口を閉じる execute_child_command(); // 子プロセスの処理を実行する exit(0); // 子プロセスを終了し、親にSIGCHILDが送信される } 子プロセス 0 1 2 4 pipe_fd[1] 標準エラー 標準出力 標準入力 書き込み 読み出し 3 pipe_fd[0]
パイプラインを使ったプロセス間通信 static void start_child_process(int *pipe_fd) { int file_fd; close(pipe_fd[PIPE_READ_FD]);
// パイプライン読み込み口を閉じる file_fd = open("access.log", O_RDONLY); // access.logファイルを開く if (file_fd == -1) { // エラー処理 } dup2(file_fd, STDIN_FILENO) // 標準入力をaccess.logファイルFDのコピーとして作成する close(file_fd); // access.logファイルFDを閉じる dup2(pipe_fd[PIPE_WRITE_FD], STDOUT_FILENO) // 標準出力をパイプライン書き込み口のコピーとして作成する close(pipe_fd[PIPE_WRITE_FD]); // パイプライン書き込み口を閉じる execute_child_command(); // 子プロセスの処理を実行する exit(0); // 子プロセスを終了し、親にSIGCHILDが送信される } 子プロセス 0 1 2 4 pipe_fd[1] 標準エラー 標準出力 標準入力 書き込み 読み出し file_fd 5 pipe_fd[0] 3
パイプラインを使ったプロセス間通信 static void start_child_process(int *pipe_fd) { int file_fd; close(pipe_fd[PIPE_READ_FD]);
// パイプライン読み込み口を閉じる file_fd = open("access.log", O_RDONLY); // access.logファイルを開く if (file_fd == -1) { // エラー処理 } dup2(file_fd, STDIN_FILENO) // 標準入力をaccess.logファイルFDのコピーとして作成する close(file_fd); // access.logファイルFDを閉じる dup2(pipe_fd[PIPE_WRITE_FD], STDOUT_FILENO) // 標準出力をパイプライン書き込み口のコピーとして作成する close(pipe_fd[PIPE_WRITE_FD]); // パイプライン書き込み口を閉じる execute_child_command(); // 子プロセスの処理を実行する exit(0); // 子プロセスを終了し、親にSIGCHILDが送信される } 子プロセス 0 → access.log 1 2 4 pipe_fd[1] 標準エラー 標準出力 標準入力 書き込み 読み出し file_fd 5 3 pipe_fd[0]
パイプラインを使ったプロセス間通信 static void start_child_process(int *pipe_fd) { int file_fd; close(pipe_fd[PIPE_READ_FD]);
// パイプライン読み込み口を閉じる file_fd = open("access.log", O_RDONLY); // access.logファイルを開く if (file_fd == -1) { // エラー処理 } dup2(file_fd, STDIN_FILENO) // 標準入力をaccess.logファイルFDのコピーとして作成する close(file_fd); // access.logファイルFDを閉じる dup2(pipe_fd[PIPE_WRITE_FD], STDOUT_FILENO) // 標準出力をパイプライン書き込み口のコピーとして作成する close(pipe_fd[PIPE_WRITE_FD]); // パイプライン書き込み口を閉じる execute_child_command(); // 子プロセスの処理を実行する exit(0); // 子プロセスを終了し、親にSIGCHILDが送信される } 子プロセス 0 → access.log 1 2 4 pipe_fd[1] 標準エラー 標準出力 標準入力 書き込み 読み出し pipe_fd[0] 3 file_fd 5
パイプラインを使ったプロセス間通信 static void start_child_process(int *pipe_fd) { int file_fd; close(pipe_fd[PIPE_READ_FD]);
// パイプライン読み込み口を閉じる file_fd = open("access.log", O_RDONLY); // access.logファイルを開く if (file_fd == -1) { // エラー処理 } dup2(file_fd, STDIN_FILENO) // 標準入力をaccess.logファイルFDのコピーとして作成する close(file_fd); // access.logファイルFDを閉じる dup2(pipe_fd[PIPE_WRITE_FD], STDOUT_FILENO) // 標準出力をパイプライン書き込み口のコピーとして作成する close(pipe_fd[PIPE_WRITE_FD]); // パイプライン書き込み口を閉じる execute_child_command(); // 子プロセスの処理を実行する exit(0); // 子プロセスを終了し、親にSIGCHILDが送信される } 子プロセス 0 → access.log 1 → pipe_fd[1] 2 4 pipe_fd[1] 標準エラー 標準出力 標準入力 書き込み 読み出し 3 pipe_fd[0] file_fd 5
パイプラインを使ったプロセス間通信 static void start_child_process(int *pipe_fd) { int file_fd; close(pipe_fd[PIPE_READ_FD]);
// パイプライン読み込み口を閉じる file_fd = open("access.log", O_RDONLY); // access.logファイルを開く if (file_fd == -1) { // エラー処理 } dup2(file_fd, STDIN_FILENO) // 標準入力をaccess.logファイルFDのコピーとして作成する close(file_fd); // access.logファイルFDを閉じる dup2(pipe_fd[PIPE_WRITE_FD], STDOUT_FILENO) // 標準出力をパイプライン書き込み口のコピーとして作成する close(pipe_fd[PIPE_WRITE_FD]); // パイプライン書き込み口を閉じる execute_child_command(); // 子プロセスの処理を実行する exit(0); // 子プロセスを終了し、親にSIGCHILDが送信される } 子プロセス 0 → access.log 1 → pipe_fd[1] 2 標準エラー 標準出力 標準入力 書き込み 読み出し pipe_fd[0] 3 pipe_fd[1] 4 5 file_fd
パイプラインを使ったプロセス間通信 static void start_child_process(int *pipe_fd) { int file_fd; close(pipe_fd[PIPE_READ_FD]);
// パイプライン読み込み口を閉じる file_fd = open("access.log", O_RDONLY); // access.logファイルを開く if (file_fd == -1) { // エラー処理 } dup2(file_fd, STDIN_FILENO) // 標準入力をaccess.logファイルFDのコピーとして作成する close(file_fd); // access.logファイルFDを閉じる dup2(pipe_fd[PIPE_WRITE_FD], STDOUT_FILENO) // 標準出力をパイプライン書き込み口のコピーとして作成する close(pipe_fd[PIPE_WRITE_FD]); // パイプライン書き込み口を閉じる execute_child_command(); // 子プロセスの処理を実行する exit(0); // 子プロセスを終了し、親にSIGCHILDが送信される } extern char **environ; // 設定されている環境変数 static void execute_child_command() { char *argv[2]; // char型2次元配列 argv[0] = "/bin/cat"; // 実行するコマンドの絶対パス argv[1] = NULL; // 2次元配列の一番後ろに NULLを代入する if (execve(argv[0], argv, environ) == -1) // プログラムを実行する { // エラー処理 } } #include <unistd.h> int execve(const char * filename , char *const argv [], char *const envp []); filename: プログラムファイルの絶対パス argv: プログラムに渡す引数の 2次元配列(NULLポインタで終端) envp: プログラムに渡す環境変数の 2次元配列(NULLポインタで終端)
パイプラインを使ったプロセス間通信 子プロセス 0 → access.log 1 → pipe_fd[1] 2
3 4 標準入力 標準出力 標準エラー pipe_fd[0] pipe_fd[1] 親プロセス 0 1 2 3 4 標準入力 標準出力 標準エラー pipe_fd[0] pipe_fd[1] 書き出し 読み出し 書き出し 読み出し パイプライン 子プロセスの処理実行時 file_fd 5
親プロセスの処理
パイプラインを使ったプロセス間通信 int main(void) { int pipe_fd[2]; pid_t pid; int
status; pipe(pipe_fd); pid = fork(); if (pid == -1) // エラー対応 { // エラー対応 } else if (pid == 0) // 子プロセス { start_child_process(pipe_fd); } else // 親プロセス { wait(&status); // 子プロセスを待つ start_parent_process(pipe_fd); } return (0); } static void start_parent_process(int *pipe_fd) { close(pipe_fd[PIPE_WRITE_FD]); // パイプライン書き込み口を閉じる dup2(pipe_fd[PIPE_READ_FD], STDIN_FILENO) // 標準入力をパイプライン読み込み口のコピーとして作成する close(pipe_fd[PIPE_READ_FD]); // パイプライン読み込み口を閉じる execute_parent_command(); // 親プロセスの処理を実行する }
パイプラインを使ったプロセス間通信 int main(void) { int pipe_fd[2]; pid_t pid; int
status; pipe(pipe_fd); pid = fork(); if (pid == -1) // エラー対応 { // エラー対応 } else if (pid == 0) // 子プロセス { start_child_process(pipe_fd); } else // 親プロセス { wait(&status); // 子プロセスを待つ start_parent_process(pipe_fd); } return (0); } static void start_child_process(int *pipe_fd) { …省略 execute_child_command(); // 子プロセスの処理を実行する exit(0); // 子プロセスを終了し、親に SIGCHILDが送信される } 子プロセス 親プロセス 終了 SIGCHILD waitの ブロッキング解除
テンプレート 親プロセス 0 1 2 3 4 標準入力 標準出力 標準エラー
pipe_fd[0] pipe_fd[1] 書き出し 読み出し static void start_parent_process(int *pipe_fd) { close(pipe_fd[PIPE_WRITE_FD]); // パイプライン書き込み口を閉じる dup2(pipe_fd[PIPE_READ_FD], STDIN_FILENO) // 標準入力をパイプライン読み込み口のコピーとして作成する close(pipe_fd[PIPE_READ_FD]); // パイプライン読み込み口を閉じる execute_parent_command(); // 親プロセスの処理を実行する }
テンプレート 親プロセス 0 → pipe_fd[0] 1 2 3 4 標準入力
標準出力 標準エラー pipe_fd[0] pipe_fd[1] 書き出し 読み出し static void start_parent_process(int *pipe_fd) { close(pipe_fd[PIPE_WRITE_FD]); // パイプライン書き込み口を閉じる dup2(pipe_fd[PIPE_READ_FD], STDIN_FILENO) // 標準入力をパイプライン読み込み口のコピーとして作成する close(pipe_fd[PIPE_READ_FD]); // パイプライン読み込み口を閉じる execute_parent_command(); // 親プロセスの処理を実行する }
テンプレート 親プロセス 0 → pipe_fd[0] 1 2 3 4 標準入力
標準出力 標準エラー pipe_fd[0] pipe_fd[1] 書き出し 読み出し static void start_parent_process(int *pipe_fd) { close(pipe_fd[PIPE_WRITE_FD]); // パイプライン書き込み口を閉じる dup2(pipe_fd[PIPE_READ_FD], STDIN_FILENO) // 標準入力をパイプライン読み込み口のコピーとして作成する close(pipe_fd[PIPE_READ_FD]); // パイプライン読み込み口を閉じる execute_parent_command(); // 親プロセスの処理を実行する }
パイプラインを使ったプロセス間通信 static void start_parent_process(int *pipe_fd) { close(pipe_fd[PIPE_WRITE_FD]); // パイプライン書き込み口を閉じる
dup2(pipe_fd[PIPE_READ_FD], STDIN_FILENO) // 標準入力をパイプライン読み込み口のコピーとして作成する close(pipe_fd[PIPE_READ_FD]); // パイプライン読み込み口を閉じる execute_parent_command(); // 親プロセスの処理を実行する } static void execute_parent_command() { char *argv[3]; // char型2次元配列 argv[0] = "/usr/bin/grep"; // 実行するコマンドの絶対パス argv[1] = "POST"; // grep で使用する引数 argv[2] = NULL; // 2次元配列の一番後ろに NULLを代入する if (execve(argv[0], argv, NULL) == -1) // プログラムを実行する { // エラー処理 } } #include <unistd.h> int execve(const char * filename , char *const argv [], char *const envp []); filename: プログラムファイルの絶対パス argv: プログラムに渡す引数の 2次元配列(NULLポインタで終端) envp: プログラムに渡す環境変数の 2次元配列(NULLポインタで終端)
パイプラインを使ったプロセス間通信 子プロセス 0 → access.log 1 → pipe_fd[1] 2
3 4 標準入力 標準出力 標準エラー pipe_fd[0] pipe_fd[1] 親プロセス 0 → pipe_fd[0] 1 2 3 4 標準入力 標準出力 標準エラー pipe_fd[0] pipe_fd[1] 書き出し 読み出し 書き出し 読み出し パイプライン 親プロセスの処理実行時 file_fd 5
パイプラインを使ったプロセス間通信 bash-3.2$ make gcc main.c -o ex04 bash-3.2$ ls
Makefile README.md access.log ex04 main.c bash-3.2$ ./ex04 5.78.198.52 - - [22/Jan/2019:03:56:26 +0330] "POST /m/updateVariation?__amp_source_origin=https%3A%2F%2Fwww.zanbil.ir HTTP/1.1" 200 171 "https://www.zanbil.ir/m/product/33978/64784/%DA%AF%D9%88%D8%B4%DB%8C-%D9%85%D9%88%D8%A8%D8%A7%DB%8C%D9%84-% D8%B3%D8%A7%D9%85%D8%B3%D9%88%D9%86%DA%AF-%D9%85%D8%AF%D9%84-Galaxy-A9-%282018%29-Dual-128GB-%28SM-A9 20%29" "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-G950F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.2 Chrome/63.0.3239.111 Mobile Safari/537.36" "-" 5.78.198.52 - - [22/Jan/2019:03:56:28 +0330] "POST /m/updateVariation?__amp_source_origin=https%3A%2F%2Fwww.zanbil.ir HTTP/1.1" 200 171 "https://www.zanbil.ir/m/product/33978/64784/%DA%AF%D9%88%D8%B4%DB%8C-%D9%85%D9%88%D8%A8%D8%A7%DB%8C%D9%84-% D8%B3%D8%A7%D9%85%D8%B3%D9%88%D9%86%DA%AF-%D9%85%D8%AF%D9%84-Galaxy-A9-%282018%29-Dual-128GB-%28SM-A9 20%29" "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-G950F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.2 Chrome/63.0.3239.111 Mobile Safari/537.36" "-" プログラム実行時の様子
ご清聴 ありがとうございました