関連記事
Goメモ-447 (mkfifoメモ)(1)(create) - いろいろ備忘録日記
Goメモ-448 (mkfifoメモ)(2)(read) - いろいろ備忘録日記
Goメモ-449 (mkfifoメモ)(3)(write) - いろいろ備忘録日記
GitHub - devlights/blog-summary: ブログ「いろいろ備忘録日記」のまとめ
概要
以下、自分用のメモです。忘れないうちにメモメモ。。。
Go側から名前付きパイプ(mkfifo)を扱うことがあったので、忘れない内にメモしておこうと思いました。
今回は名前付きパイプファイルからの読み込み(ノンブロッキングモード)について。
なお、標準ライブラリにある syscall
パッケージの Mkfifo()
でも行えるのですが
サンプルでは sys/unix の方を使っています。
サンプル
//go:build linux package main import ( "bufio" "errors" "flag" "fmt" "io" "log" "os" "sync" "time" "golang.org/x/sys/unix" ) var ( fname string ) func init() { log.SetFlags(log.Lmicroseconds) flag.StringVar(&fname, "fname", "", "FIFO file name") flag.Parse() } func main() { if err := run(); err != nil { log.Fatal(err) } } func run() error { // // 名前付きパイプをノンブロッキングモードで開く // 明示的なノンブロッキングモードの指定は os.OpenFile() では行えないため // golang.org/x/sys/unix を利用する // var ( fd int f *os.File err error ) log.Println("[Before] unix.Open(unix.O_RDONLY|unix.O_NONBLOCK)") fd, err = unix.Open(fname, unix.O_RDONLY|unix.O_NONBLOCK, 0666) if err != nil { return err } f = os.NewFile(uintptr(fd), fname) if f == nil { return fmt.Errorf("invalid file descriptor") } defer f.Close() // ここで f.Close() しているので、上で unix.Close(fd) は不要 log.Println("[After ] unix.Open(unix.O_RDONLY|unix.O_NONBLOCK)") // // データを読み取り // type ( data struct { value string err error } ) var ( reader = bufio.NewReader(f) lines = make(chan data) timeout = 1500 * time.Millisecond done = make(chan struct{}) wg sync.WaitGroup ) wg.Add(1) go func() { defer wg.Done() // ノンブロッキングモードで処理しているため、データが存在しない場合は即EOFが返ってくる for { line, err := reader.ReadString('\n') if err != nil && errors.Is(err, io.EOF) { log.Println("読み取れるデータが存在しない") select { case <-done: return case <-time.After(200 * time.Millisecond): continue } } lines <- data{line, err} return } }() select { case line := <-lines: if line.err != nil { return line.err } log.Println(line.value) case <-time.After(timeout): log.Println("timeout") } close(done) wg.Wait() return nil }
実行すると以下のようになります。
$ task task: [build] go build -o app . task: [create-fifo] rm -f ./tmp-fifo task: [create-fifo] mkfifo ./tmp-fifo -m0666 task: [run] (sleep 1; echo "helloworld" > ./tmp-fifo) & task: [run] ./app -fname ./tmp-fifo 05:25:35.397135 [Before] unix.Open(unix.O_RDONLY|unix.O_NONBLOCK) 05:25:35.397320 [After ] unix.Open(unix.O_RDONLY|unix.O_NONBLOCK) 05:25:35.397368 読み取れるデータが存在しない 05:25:35.597705 読み取れるデータが存在しない 05:25:35.798143 読み取れるデータが存在しない 05:25:35.998529 読み取れるデータが存在しない 05:25:36.198859 読み取れるデータが存在しない 05:25:36.399736 helloworld
ノンブロッキングモードでオープンしているので、ファイルを開く部分ではブロックされなくなります。
代わりに Read する部分にて、まだ読み取れるデータが存在しない場合に即 io.EOF が返ってきます。
参考情報
6.3 Named Pipes (FIFOs - First In First Out)
Ubuntu Manpage: mkfifo, mkfifoat - FIFOスペシャルファイル(名前付きパイプ)を作成する
Master the Linux ‘mkfifo’ Command: A Comprehensive Guide | by Peter Hou | Medium
Goのおすすめ書籍
過去の記事については、以下のページからご参照下さい。
サンプルコードは、以下の場所で公開しています。