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
450
パイプラインによるプロセス間通信を理解する
社内向け勉強会に用意した資料「パイプラインによるプロセス間通信を理解する」です。
Kotaro Kamashima
October 30, 2022
Tweet
Share
More Decks by Kotaro Kamashima
See All by Kotaro Kamashima
読書シェア会 vol.4 『ダイナミックリチーミング 第2版』
kotaro666
0
130
Navigation Bar と権限管理
kotaro666
0
32
Other Decks in Programming
See All in Programming
設計やレビューに悩んでいるPHPerに贈る、クリーンなオブジェクト設計の指針たち
panda_program
6
1.9k
イベントストーミング図からコードへの変換手順 / Procedure for Converting Event Storming Diagrams to Code
nrslib
2
640
PHPでWebSocketサーバーを実装しよう2025
kubotak
0
270
新メンバーも今日から大活躍!SREが支えるスケールし続ける組織のオンボーディング
honmarkhunt
3
6k
データの民主化を支える、透明性のあるデータ利活用への挑戦 2025-06-25 Database Engineering Meetup#7
y_ken
0
340
たった 1 枚の PHP ファイルで実装する MCP サーバ / MCP Server with Vanilla PHP
okashoi
1
230
Railsアプリケーションと パフォーマンスチューニング ー 秒間5万リクエストの モバイルオーダーシステムを支える事例 ー Rubyセミナー 大阪
falcon8823
5
1.1k
Modern Angular with Signals and Signal Store:New Rules for Your Architecture @enterJS Advanced Angular Day 2025
manfredsteyer
PRO
0
200
Select API from Kotlin Coroutine
jmatsu
1
230
AIプログラマーDevinは PHPerの夢を見るか?
shinyasaita
1
200
LINEヤフー データグループ紹介
lycorp_recruit_jp
0
2.2k
「Cursor/Devin全社導入の理想と現実」のその後
saitoryc
0
770
Featured
See All Featured
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
8
810
The Cost Of JavaScript in 2023
addyosmani
51
8.5k
For a Future-Friendly Web
brad_frost
179
9.8k
Designing for Performance
lara
610
69k
Responsive Adventures: Dirty Tricks From The Dark Corners of Front-End
smashingmag
252
21k
XXLCSS - How to scale CSS and keep your sanity
sugarenia
248
1.3M
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
138
34k
Rails Girls Zürich Keynote
gr2m
94
14k
Why Our Code Smells
bkeepers
PRO
337
57k
Improving Core Web Vitals using Speculation Rules API
sergeychernyshev
18
960
Automating Front-end Workflow
addyosmani
1370
200k
Build your cross-platform service in a week with App Engine
jlugia
231
18k
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" "-" プログラム実行時の様子
ご清聴 ありがとうございました