👌

IPCメモ

2024/07/23に公開

pipe

同じパイプに対して親子プロセスがともに読み取ろうとすることはまずない。
2プロセスが同時にパイプから読み取ると、どちらかが成功するかが保証できない競合状態になる。これを回避するには何らかの同期が必要。

双方向通信するなら、2つのパイプを作って、1つを送信用、1つを受信用とする方が楽。
ただし、デッドロックに注意

読み取りプロセスが書き込み口をクローズする理由は、書き込みプロセスが書き込み終わって書き込み口をクローズ後にEOFを読み取れない。

書き込みプロセスが読み取り側をクローズするのはwrite()がbroken pipeエラーになった時の対応を実装するため。
書き込もうとしたときに、プロセスの読み取りファイルディスクリプタをオープンしているプロセスが存在しない場合、カーネルがプロセスへSIGPIPEシグナルを送信する。

  • SIGPIPEのデフォルト動作はシグナルの終了。このシグナルは捕捉/無視が可能で、パイプへのwrite()がEPIPE("broken pipe")になった時の対応を実装できる。

FIFO

読み込み側と書き込み側の両方がオープンされるまでブロックする。
O_RDWRフラグをセットするとブロックせず、読み込み書き込み両方に使えるfdを返すが、これは実行環境によっては未定義動作なのであまりよくはない。
どうしてもブロックしたくなければ、O_NONBLOCKフラグをセットする。

umask set file mode creation mask
どのようなアクセス権(パーミッション)をマスクするかを決めます。
umask(0)は何もマスクしないんじゃない?
https://qiita.com/saito_now/items/26dd64666e996be53850

    // サーバがクライアントFIFOへ書き込んだがクライアントがクライアントFIFOを読み取らないとき
    // SIGPIPEが発生するのを避け、write()のエラーとする
    // SIGPIPEはハンドリングしないとプロセスを強制終了させる
    if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
        errExit("signal");
    

これは以下で詳細に解説がある。Goでの実験もついているのでやる
https://christina04.hatenablog.com/entry/pipe-error-handling

C言語

snprintf

int snprintf(char* s, size_t n, char* format, ...);
snprintf(clientFifo, CLINET_FIFO_NAME_LEN, CLINET_FIFO_TEMPLATE, (long) getpid());

formatを成型した文字列をsに格納する

read

ssize_t read(int fd, void *buf, size_t byte)
fdからbyteバイト読み取りbufに格納する

write

int write(int fd, void *buf, unsined int byte)
bufからbyteバイトをfdに書き込む

signal

シグナルをハンドリングする。
void (*signal(int sig, void (*func)(int)))(int);
sig: シグナル番号
func: シグナルハンドラ
signal(SIGPIPE, SIG_IGN)は、SIGPIPEを無視する。

Discussion