thread-safe is not fiber-safe; fiber-safe could be even harder
Other posts:
2148. 04-04 thread-safe is not fiber-safe; fiber-safe could be even harder
2149. 04-04 thread-safe is not fiber-safe; fiber-safe could be even harder (2)
2151. 04-05 thread-safe is not fiber-safe; fiber-safe could be even harder (3)
concurrency with shared state is really hard!
2148. 04-04 thread-safe is not fiber-safe; fiber-safe could be even harder
2149. 04-04 thread-safe is not fiber-safe; fiber-safe could be even harder (2)
2151. 04-05 thread-safe is not fiber-safe; fiber-safe could be even harder (3)
deterministic race conditions in fibers
i = [0]
a = Fiber.new{ t = i[0]; Fiber.yield; i[0] = t + 1 }
b = Fiber.new{ t = i[0]; Fiber.yield; i[0] = t + 1 }
p i # => [0]
a.resume
b.resume
a.resume # 1
b.resume # 1
p i # => [1] # should be [2]
thread-safe code is not fiber-safe, here we have deadlock
m = Mutex.new
i = [0]
a = Fiber.new{ m.synchronize{ t = i[0]; Fiber.yield; i[0] = t + 1 } }
b = Fiber.new{ m.synchronize{ t = i[0]; Fiber.yield; i[0] = t + 1 } }
p i # => [0]
a.resume
b.resume # ThreadError: deadlock; recursive locking
reentrant mutex doesn't really lock for fibers. it still has race conditions
require 'monitor'
m = Monitor.new
i = [0]
a = Fiber.new{ m.synchronize{ t = i[0]; Fiber.yield; i[0] = t + 1 } }
b = Fiber.new{ m.synchronize{ t = i[0]; Fiber.yield; i[0] = t + 1 } }
p i # => [0]
a.resume
b.resume
a.resume # 1
b.resume # 1
p i # => [1] # should be [2]
detect deadlock and retry with threads to resume fibers again, finally fiber-safe now
require 'fiber'
def try_resume f
case r = f.resume
when ThreadError
Thread.new{ sleep(0.1); try_resume(f) }
else
r
end if f.alive?
end
m = Mutex.new
i = [0]
a = Fiber.new{
begin
m.synchronize{ t = i[0]; Fiber.yield; i[0] = t + 1 }
rescue ThreadError => e
Fiber.yield e
retry
end
}
b = Fiber.new{
begin
m.synchronize{ t = i[0]; Fiber.yield; i[0] = t + 1 }
rescue ThreadError => e
Fiber.yield e
retry
end
}
p i # => [0]
while a.alive? || b.alive?
try_resume(a)
try_resume(b)
end
p i # => [2]
retry with eventmachine instead, but do we really want to do this?
require 'fiber'
require 'eventmachine'
def try_resume f
case r = f.resume
when ThreadError
EM.add_timer(0.1){ try_resume(f) }
else
r
end if f.alive?
end
EM.run{
m = Mutex.new
i = [0]
a = Fiber.new{
begin
m.synchronize{ t = i[0]; Fiber.yield; i[0] = t + 1 }
rescue ThreadError => e
Fiber.yield e
retry
end
}
b = Fiber.new{
begin
m.synchronize{ t = i[0]; Fiber.yield; i[0] = t + 1 }
rescue ThreadError => e
Fiber.yield e
retry
end
}
p i # => [0]
try_resume(a)
try_resume(b)
EM.add_periodic_timer(0.1){
try_resume(a)
try_resume(b)
if !a.alive? && !b.alive?
p i # => [2]
EM.stop
end
}
}
can STM (software transactional memory) help here?
STM for Ruby WANTED!!or let's just use threads, shall we?
m = Mutex.new
i = [0]
a = Thread.new{ m.synchronize{ t = i[0]; sleep(0.1); i[0] = t + 1 } }
b = Thread.new{ m.synchronize{ t = i[0]; sleep(0.1); i[0] = t + 1 } }
p i # => [0]
a.join
b.join
p i # => [2]
--concurrency with shared state is really hard!
0 retries:
Post a Comment
Note: Only a member of this blog may post a comment.