鈴木さん、首藤と申します。

シグナルには、
特定のスレッドに配送されるものと、プロセスに配送されるものがあります。
少し調べたところ、Linux では、
SIGCHLD はプロセスに配送されるようです。

では、どのスレッドに配送されるかというと…
あるウェブページによると、
そのシグナルをブロックしていないスレッドのうちの「どれか」だそうです。
特定のスレッドに配送してもらいたければ、
そのシグナルを他のすべてのスレッドでブロックしておく、という手があるようです。

ほんとは、POSIX での規定はどうなっているか? などにも興味あるのですが、
そこまでは調べておりません。


スレッドもシグナルも、どちらも非同期処理の機構であって、
噛み合わせがとても悪いですよね。

Ruby は、OS ごとの違いを吸収する、ということは狙っておらず、
今回のように、OS やバージョンの違いで挙動の違いが (当然) 出てくる、と。

Kazuyuki Shudo/首藤一幸   私をたばねないで あらせいとうの花のように
  2015 / shudo.net   http://www.shudo.net/


> Message-ID: <CADAs0bA5-p6stvofYomm=dwWEQh2dM-6TMHqxe2K0rFRQdCpmw / mail.gmail.com>
> From: Norio Suzuki <nosuzuki / postcard.st>
> Date: Mon, 9 Feb 2015 19:57:14 +0900

> 1.9.3から2系列にやっと重い腰を上げて移行を始めた鈴木と申します。
>
> 移行中にもしかしたらバグかもしれない現象にあったので報告いたします。もう2.2がリリースされているので、仕様の変更によるものでこれが設計通りの動作なのだとは思いますが、一応。
>
> # 現象
>
> Thread内で作成した子プロセスが終了してもSIGCHLDが親プロセスに送られてこない。
>
> 子プロセスが終了すると送られてくるSIGCHLDをtrapしてwaitすることで子プロセスがゾンビ化するのを防ぎたいのですが、Thread内で作成すると子プロセスが終了してもSIGCHLDをtrapすることができません。
>
> またProcess.detach()を使ってみたのですが、Thread内だと同様にゾンビになってしまいました。
>
> この現象はRubyのバージョンに依存しています。2.0と2.1ではこの問題が起きますが、1.9.3ではThread内でプロセスを作成しても、SIGCHLDを捕まえられます。
>
> # テスト環境
>
> Ubuntu 14.04.1
>   ruby 1.9.3p484 (2013-11-22 revision 43786) [x86_64-linux]
> SIGCHLDを捕まえられる。
>
> Ubuntu 14.04.1
>   ruby 2.0.0p384 (2014-01-12) [x86_64-linux-gnu]
> Ubuntu 14.10
>   ruby 2.1.2p95 (2014-05-08) [x86_64-linux-gnu]
> SIGCHLDを捕まえられない。
>
> # テストプログラム
>
> #!/usr/bin/ruby
> # -*- coding: utf-8 -*-
>
> Signal.trap(:CHLD){
>   begin
>     while status = Process.waitpid2(-1, Process::WNOHANG|Process::WUNTRACED)
>       print "SIGCHLD: pid_#{status.first}: #{status.last.inspect}\n"
>     end
>   rescue Errno::ECHILD
>     print "SIGCHLD: Errno::ECHILD\n"
>   end
> }
>
> def spawn_proc(from)
>   if pid = fork
>     print "spawn proc(#{pid})\n"
>     # Process.detach(pid) # not work
>   else
>     sleep 1
>
>     server(from)
>     exit
>   end
> end
>
> def server(from)
>   print "#{$$}: forked in #{from}\n"
>   sleep rand(10)
>   print "#{$$}: exit\n"
>   exit
> end
>
> Thread.start{
>   3.times{
>     spawn_proc("thread")
>   }
> }
>
> 3.times{
>   spawn_proc("main")
> }
>
> sleep 30
>
> -- 
> 鈴木教郎