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
Sponsored
·
SiteGround - Reliable hosting with speed, security, and support you can count on.
→
Kotaro Kamashima
October 30, 2022
Programming
650
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
パイプラインによるプロセス間通信を理解する
社内向け勉強会に用意した資料「パイプラインによるプロセス間通信を理解する」です。
Kotaro Kamashima
October 30, 2022
More Decks by Kotaro Kamashima
See All by Kotaro Kamashima
読書シェア会 vol.7『Nonviolent Communication: A Language of Life』を再読してみて
kotaro666
0
29
読書シェア会 vol.4 『ダイナミックリチーミング 第2版』
kotaro666
0
220
Navigation Bar と権限管理
kotaro666
0
65
Other Decks in Programming
See All in Programming
Discordを用いたラボオートメーション関連情報収集の自動化
noguhiro2002
0
500
DynamoDBの基礎を振り返りながらベクトル検索機能を理解する
musan
3
270
Swift愛好会と私(ウホーイ) / Swift Fan Club and Uhooi
uhooi
0
140
RSSとCodexを使ってX投稿自動化してみた
ochtum
0
110
Hono + Inertia + React で LP を構築した話
oukayuka
2
210
初めての模倣学習とVLA
natsutan
0
490
AI駆動開発にグラフDBを重ねてみた
satoshi256kbyte
2
750
スマート反転とウェブアクセシビリティ
camiha
0
120
信頼性の目標を誰も求めてない
shubox
0
490
一参加者から『中の人』へ 〜全通PHPerがブースに立って学んだ、カンファレンスを100倍楽しむコツ〜
wp_daisuke
0
120
片田舎のおっさん、 Swift Buildのダイアモンド問題解決の不具合修正PRを出すが、解決方法がキャッシュをしないようにすることであり、ビルド時間が伸びると言われてマージされないので高速化もする/swiftbuild
yimajo
0
360
in-process GraphQL のすすめ #ginzajs
izumin5210
4
1.5k
Featured
See All Featured
The Straight Up "How To Draw Better" Workshop
denniskardys
239
140k
Ecommerce SEO: The Keys for Success Now & Beyond - #SERPConf2024
aleyda
1
2.1k
Leading Effective Engineering Teams in the AI Era
addyosmani
9
2.5k
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
32
4.6k
The Invisible Side of Design
smashingmag
301
52k
State of Search Keynote: SEO is Dead Long Live SEO
ryanjones
0
260
Fireside Chat
paigeccino
42
4k
Exploring the relationship between traditional SERPs and Gen AI search
raygrieselhuber
PRO
2
4.3k
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
31
10k
Odyssey Design
rkendrick25
PRO
2
800
A Guide to Academic Writing Using Generative AI - A Workshop
ks91
PRO
1
420
For a Future-Friendly Web
brad_frost
183
10k
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" "-" プログラム実行時の様子
ご清聴 ありがとうございました