Engineering from Scratch

エンジニア目指してます

2022/06/11

Unix Processes

Our First Pipe

複数プロセス間でのやり取りにパイプを使用する。パイプはデータを単方向通信する。writerがwriteした内容をreaderがreadできる。

irb(main):001:0> reader, writer = IO.pipe
=> [#<IO:fd 9>, #<IO:fd 10>]
irb(main):002:0> writer.write("Into the pipe I go...")
=> 21
irb(main):003:0> writer.close
=> nil
irb(main):004:0> puts reader.read
Into the pipe I go...
=> nil      

writeがcloseしてからでないと,readerはreadできない。

Sharing Pipes

親と子プロセス間で,リソースは共有されるため,pipeも共有される。

irb(main):001:0> reader, writer = IO.pipe
=> [#<IO:fd 9>, #<IO:fd 10>]
irb(main):002:1* fork do
irb(main):003:1*   reader.close
irb(main):004:1*   
irb(main):005:2*   10.times do
irb(main):006:2*     writer.puts "Another one bites the dust"
irb(main):007:1*   end
irb(main):008:0> end
=> 15983
irb(main):009:0> writer.close
=> nil
irb(main):010:1* while message = reader.gets
irb(main):011:1*   $stdout.puts message
irb(main):012:0> end
Another one bites the dust
Another one bites the dust                                              
Another one bites the dust                                              
Another one bites the dust                                              
Another one bites the dust                                              
Another one bites the dust                                              
Another one bites the dust                                              
Another one bites the dust                                              
Another one bites the dust                                              
Another one bites the dust   

上記の例だと,親プロセスにwriterとreader,子プロセスにwriterとreaderがそれぞれ存在するため,不要な子プロセスのreader,親プロセスのwriterをcloseしている。

Stream vs. Messages

Unix Socketsは同じ物理マシン上でやり取りできるソケットの一種。TCPソケットよりも高速。ソケットでは双方向通信が可能。

irb(main):001:0> require "socket"
=> true
irb(main):002:0> child_socket, parent_socket = Socket.pair(:UNIX, :DGRAM, 0)
=> [#<Socket:fd 9>, #<Socket:fd 10>]
irb(main):003:0> max_len = 1000
=> 1000
irb(main):004:1* fork do
irb(main):005:1*   parent_socket.close
irb(main):006:1*   
irb(main):007:2*   4.times do
irb(main):008:2*     instruction = child_socket.recv(max_len)
irb(main):009:2*     child_socket.send("#{instruction} accomplished!", 0)
irb(main):010:1*   end
irb(main):011:0> end
=> 16197
irb(main):012:0> child_socket.close
=> nil
irb(main):013:1* 2.times do
irb(main):014:1*   parent_socket.send("Heavy lifting", 0)
irb(main):015:0> end
=> 2
irb(main):016:1* 2.times do
irb(main):017:1*   parent_socket.send("Feather lifting", 0)
irb(main):018:0> end
=> 2
irb(main):019:1* 4.times do
irb(main):020:1*   $stdout.puts parent_socket.recv(max_len)
irb(main):021:0> end
Heavy lifting accomplished!
Heavy lifting accomplished!                                                    
Feather lifting accomplished!                                                  
Feather lifting accomplished!  

子プロセスが親プロセスから受信したメッセージに文字列を加えて,親プロセスに送信し,最後に親プロセスが受信したメッセージを出力している。

Daemon Processes

daemon processは,ターミナル上でユーザが支配できるというよりは,裏で動いているプロセス。代表的な例は,WebサーバーやDBサーバー。

参考

workingwithruby.com