summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormame <mame@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2010-04-16 11:10:08 +0000
committermame <mame@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2010-04-16 11:10:08 +0000
commit93c5002a7c3a157e0b3cd4192a7f26f32677562c (patch)
tree2bacba4d3ad2fc7e26dc6d3878daac26d0f2df8a
parent7d26c313a12a174c27576e4c55fb76b1ff62de7e (diff)
* lib/thread.rb (Queue#push, #pop, SizedQueue#push, #pop): remove
code that kicks waiting thread twice, which caused race and deadlock. [ruby-core:25537] * test/thread/test_queue.rb: added. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@27356 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r--ChangeLog8
-rw-r--r--lib/thread.rb24
-rw-r--r--test/thread/test_queue.rb38
3 files changed, 50 insertions, 20 deletions
diff --git a/ChangeLog b/ChangeLog
index 2f634ca1e7..3050e9126a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+Fri Apr 16 20:05:24 2010 Yusuke Endoh <mame@tsg.ne.jp>
+
+ * lib/thread.rb (Queue#push, #pop, SizedQueue#push, #pop): remove
+ code that kicks waiting thread twice, which caused race and
+ deadlock. [ruby-core:25537]
+
+ * test/thread/test_queue.rb: added.
+
Fri Apr 16 20:01:47 2010 Yusuke Endoh <mame@tsg.ne.jp>
* .gitignore: updated.
diff --git a/lib/thread.rb b/lib/thread.rb
index 4f296bb8b3..f3831a7425 100644
--- a/lib/thread.rb
+++ b/lib/thread.rb
@@ -150,7 +150,6 @@ class Queue
# Pushes +obj+ to the queue.
#
def push(obj)
- t = nil
@mutex.synchronize{
@que.push obj
begin
@@ -160,10 +159,6 @@ class Queue
retry
end
}
- begin
- t.run if t
- rescue ThreadError
- end
end
#
@@ -182,8 +177,8 @@ class Queue
# thread isn't suspended, and an exception is raised.
#
def pop(non_block=false)
- while true
- @mutex.synchronize{
+ @mutex.synchronize{
+ while true
if @que.empty?
raise ThreadError, "queue empty" if non_block
@waiting.push Thread.current
@@ -191,8 +186,8 @@ class Queue
else
return @que.shift
end
- }
- end
+ end
+ }
end
#
@@ -295,7 +290,6 @@ class SizedQueue < Queue
# until space becomes available.
#
def push(obj)
- t = nil
@mutex.synchronize{
while true
break if @que.length < @max
@@ -311,11 +305,6 @@ class SizedQueue < Queue
retry
end
}
-
- begin
- t.run if t
- rescue ThreadError
- end
end
#
@@ -333,7 +322,6 @@ class SizedQueue < Queue
#
def pop(*args)
retval = super
- t = nil
@mutex.synchronize {
if @que.length < @max
begin
@@ -344,10 +332,6 @@ class SizedQueue < Queue
end
end
}
- begin
- t.run if t
- rescue ThreadError
- end
retval
end
diff --git a/test/thread/test_queue.rb b/test/thread/test_queue.rb
new file mode 100644
index 0000000000..087002966e
--- /dev/null
+++ b/test/thread/test_queue.rb
@@ -0,0 +1,38 @@
+require 'test/unit'
+require 'thread'
+
+class TestQueue < Test::Unit::TestCase
+ def test_queue
+ grind(5, 1000, 15, Queue)
+ end
+
+ def test_sized_queue
+ grind(5, 1000, 15, SizedQueue, 1000)
+ end
+
+ def grind(num_threads, num_objects, num_iterations, klass, *args)
+ from_workers = klass.new(*args)
+ to_workers = klass.new(*args)
+
+ workers = (1..num_threads).map {
+ Thread.new {
+ while object = to_workers.pop
+ from_workers.push object
+ end
+ }
+ }
+
+ Thread.new {
+ num_iterations.times {
+ num_objects.times { to_workers.push 99 }
+ num_objects.times { from_workers.pop }
+ }
+ }.join
+
+ num_threads.times { to_workers.push nil }
+ workers.each { |t| t.join }
+
+ assert 0, from_workers.size
+ assert 0, to_workers.size
+ end
+end