Project

General

Profile

Actions

Bug #6822

closed

Race Condition with Fiber and Process

Bug #6822: Race Condition with Fiber and Process

Added by MartinBosslet (Martin Bosslet) about 13 years ago. Updated about 13 years ago.

Status:
Closed
Target version:
ruby -v:
ruby 2.0.0dev (2012-05-07 trunk 35550) [x86_64-linux]
Backport:
[ruby-core:46922]

Description

If I run the following code

$stdout.sync = true
objects = [1, 2, 3]

fiber = Fiber.new do
  loop do
    objects.each { |obj| Fiber.yield(obj) }
  end
end

def run(obj)
  fork do
    puts obj
  end
end

def on_child_exit(obj)
  begin
    while Process.wait(-1, Process::WNOHANG)
      run(obj)
    end
  rescue Errno::ECHILD
  end
end

trap(:CHLD) { on_child_exit(fiber.resume) }
4.times { run(fiber.resume) }
sleep

I get

fiber_process.rb:26:in `resume': double resume (FiberError)

or

fiber_process.rb:26:in `resume': fiber called across stack rewinding barrier (FiberError)

There is a race condition when two or more children exit. Now I know I can implement
this differently, but this still made me curious. Is this a bug? Let's say I would
need to use a Fiber, then there is no way how I can do the synchronization manually,
or is there? Using a Mutex to synchronize the Fiber#resume will fail due to the
non-reentrant behaviour of Mutex#lock (I'll get "in `lock': deadlock; recursive
locking (ThreadError)"). Is there a way to do this or should Fibers not be used in
this context?

Updated by shyouhei (Shyouhei Urabe) about 13 years ago Actions #1 [ruby-core:46927]

  • Category changed from core to YARV
  • Status changed from Open to Assigned
  • Assignee set to ko1 (Koichi Sasada)

Updated by ko1 (Koichi Sasada) about 13 years ago Actions #2 [ruby-core:47637]

  • Category changed from YARV to core
  • Status changed from Assigned to Closed

In general, you can sync with variables because Fibers are not changed automatically. In other words, you can completely control Fiber transition.

Updated by MartinBosslet (Martin Bosslet) about 13 years ago Actions #3

ko1 (Koichi Sasada) wrote:

In general, you can sync with variables because Fibers are not changed automatically. In other words, you can completely control Fiber transition.

Thanks for looking into this. With your input, I found a way to safely synchronize the exiting childs by using Mutex#try_lock. Thank you!

Updated by ko1 (Koichi Sasada) about 13 years ago Actions #4 [ruby-core:47647]

(2012/09/21 22:14), MartinBosslet (Martin Bosslet) wrote:

Issue #6822 has been updated by MartinBosslet (Martin Bosslet).

ko1 (Koichi Sasada) wrote:

In general, you can sync with variables because Fibers are not changed automatically. In other words, you can completely control Fiber transition.

Thanks for looking into this. With your input, I found a way to safely synchronize the exiting childs by using Mutex#try_lock. Thank you!

No. You don't need Mutex at all.
You only need to use variables (such as global variables).

--
// SASADA Koichi at atdot dot net

Updated by MartinBosslet (Martin Bosslet) about 13 years ago Actions #5 [ruby-core:47648]

ko1 (Koichi Sasada) wrote:

No. You don't need Mutex at all.
You only need to use variables (such as global variables).

Now I'm confused. How would I write the example code without getting the FiberErrors? Since I have no control over when a child process exits, I can't control when the 'trap(:CHLD)' block calls Fiber#resume, no? I thought I would have to do some form of manual synchronization there, to avoid the race condition. Sorry to bug you :)

Updated by ko1 (Koichi Sasada) about 13 years ago Actions #6 [ruby-core:47692]

(2012/09/22 15:45), MartinBosslet (Martin Bosslet) wrote:

No. You don't need Mutex at all.
You only need to use variables (such as global variables).
Now I'm confused. How would I write the example code without getting the FiberErrors? Since I have no control over when a child process exits, I can't control when the 'trap(:CHLD)' block calls Fiber#resume, no? I thought I would have to do some form of manual synchronization there, to avoid the race condition. Sorry to bug you :)

Now, I understand your issue. This is not a Fiber problem, but
concurrency problem with signal.

I recommend that you shouldn't use Fiber.resume in a trap handler. In
the trap handler, you should only set a flag and make flag sense in main.

--
// SASADA Koichi at atdot dot net

Updated by MartinBosslet (Martin Bosslet) about 13 years ago Actions #7 [ruby-core:47698]

ko1 (Koichi Sasada) wrote:

Now, I understand your issue. This is not a Fiber problem, but
concurrency problem with signal.

I recommend that you shouldn't use Fiber.resume in a trap handler. In
the trap handler, you should only set a flag and make flag sense in main.

Thanks for the advice, I will do that! Thanks for bearing with me ;)

Actions

Also available in: PDF Atom