thread_tools 0.26 → 0.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.rdoc +14 -1
- data/lib/thread_tools/debugmutex.rb +26 -9
- data/lib/thread_tools/mongrel_pool.rb +15 -4
- data/lib/thread_tools/semaphore.rb +11 -4
- data/lib/thread_tools/threadpool.rb +21 -14
- data/test/test_debugmutex.rb +5 -0
- data/test/test_semaphore.rb +1 -1
- data/thread_tools.gemspec +1 -1
- metadata +1 -1
data/README.rdoc
CHANGED
@@ -6,7 +6,7 @@
|
|
6
6
|
|
7
7
|
A collection of utilities that I often use for threaded code.
|
8
8
|
|
9
|
-
== FEATURES
|
9
|
+
== FEATURES:
|
10
10
|
|
11
11
|
* Thread pool
|
12
12
|
* Mongrel patch (thread pool)
|
@@ -40,6 +40,19 @@ A collection of utilities that I often use for threaded code.
|
|
40
40
|
server = Mongrel::HttpServer.new(host, port)
|
41
41
|
server.run(10).join
|
42
42
|
|
43
|
+
* An annoying mutex
|
44
|
+
require 'thread_tools/debugmutex'
|
45
|
+
mtxA = ThreadTools::DebugMutex.new
|
46
|
+
mtxB = ThreadTools::DebugMutex.new
|
47
|
+
begin
|
48
|
+
mtxA.lock
|
49
|
+
mtxB.lock
|
50
|
+
mtxA.unlock # <= kboom!!!
|
51
|
+
rescue
|
52
|
+
# Warning, the next line unlocks all mutex acquired by this thread
|
53
|
+
ThreadTools::DebugMutex.unlock_all(Thread.current)
|
54
|
+
end
|
55
|
+
|
43
56
|
== REQUIREMENTS:
|
44
57
|
|
45
58
|
* Mongrel patch requires mongrel (duh)
|
@@ -1,15 +1,29 @@
|
|
1
|
-
#
|
2
|
-
#
|
3
|
-
#
|
4
|
-
# Mutex
|
1
|
+
# = Synopsis
|
2
|
+
# An annoying mutex for debugging
|
5
3
|
#
|
4
|
+
# = Description
|
6
5
|
# This class will make things slower, expect more contentions than normal, so
|
7
|
-
#
|
8
|
-
#
|
6
|
+
# <b>do not</b> use it to protect small blocks or tight loops.
|
9
7
|
# I derived this mutex because I needed to check contention levels, trace
|
10
|
-
# ownership changes and catch simple lock inversions
|
8
|
+
# ownership changes and catch simple lock inversions.
|
9
|
+
#
|
10
|
+
# Tip:: Use .inspect method to get a small report.
|
11
11
|
#
|
12
|
-
#
|
12
|
+
# = Usage
|
13
|
+
# mtxA = ThreadTools::DebugMutex.new
|
14
|
+
# mtxB = ThreadTools::DebugMutex.new
|
15
|
+
# begin
|
16
|
+
# mtxA.lock
|
17
|
+
# mtxB.lock
|
18
|
+
# mtxA.unlock # <= kboom!!!
|
19
|
+
# rescue
|
20
|
+
# ThreadTools::DebugMutex.unlock_all(Thread.current)
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
#
|
24
|
+
# Author:: Daniel Tralamazza
|
25
|
+
# License:: {MIT # License.}[http://www.opensource.org/licenses/mit-license.php]
|
26
|
+
|
13
27
|
|
14
28
|
require 'thread'
|
15
29
|
|
@@ -20,8 +34,11 @@ module ThreadTools
|
|
20
34
|
end
|
21
35
|
|
22
36
|
class DebugMutex < Mutex
|
37
|
+
# number of out of order unlocks
|
23
38
|
attr_reader :out_of_order_locks
|
39
|
+
# number of contentions
|
24
40
|
attr_reader :contentions
|
41
|
+
# owner thread, nil if unlocked
|
25
42
|
attr_reader :owner
|
26
43
|
|
27
44
|
def initialize
|
@@ -85,7 +102,7 @@ module ThreadTools
|
|
85
102
|
"Owner #{@owner}, Contentions #{@contentions}, Out of order acquisitions #{@out_of_order_locks}"
|
86
103
|
end
|
87
104
|
|
88
|
-
#
|
105
|
+
# *thread* thread object
|
89
106
|
def self.unlock_all(thread)
|
90
107
|
thread[:locks].reverse_each do |l|
|
91
108
|
l.unlock
|
@@ -1,10 +1,21 @@
|
|
1
|
-
#
|
2
|
-
#
|
1
|
+
# = Synopsis
|
2
|
+
# Quick and dirty patch to mongrel
|
3
3
|
#
|
4
|
+
# = Description
|
4
5
|
# This code patches mongrel to use a thread pool instead of creating a new thread
|
5
|
-
# for every request. It also traps SIGTERM to close all connections
|
6
|
-
#
|
6
|
+
# for every request. It also traps SIGTERM to close all connections.
|
7
|
+
# I also changed the run method to accept an extra parameter to set thread pool size.
|
7
8
|
#
|
9
|
+
# = Usage
|
10
|
+
# Just add <tt>require 'thread_tools/mongrel_patch'</tt> after the mongrel require
|
11
|
+
# require 'mongrel'
|
12
|
+
# require 'thread_tools/mongrel_pool'
|
13
|
+
#
|
14
|
+
# server = Mongrel::HttpServer.new(host, port)
|
15
|
+
# server.run(10).join
|
16
|
+
#
|
17
|
+
# Author:: Daniel Tralamazza
|
18
|
+
# License:: {MIT # License.}[http://www.opensource.org/licenses/mit-license.php]
|
8
19
|
|
9
20
|
|
10
21
|
require File.expand_path(File.dirname(__FILE__)+'/threadpool')
|
@@ -1,9 +1,16 @@
|
|
1
|
-
#
|
2
|
-
#
|
1
|
+
# = Synopsis
|
2
|
+
# Stupid simple semaphore
|
3
3
|
#
|
4
|
-
#
|
4
|
+
# = Description
|
5
|
+
# ...
|
5
6
|
#
|
6
|
-
|
7
|
+
# = Usage
|
8
|
+
# sem = ThreadTools::Semaphore.new(1)
|
9
|
+
# sem.acquire
|
10
|
+
# sem.release
|
11
|
+
#
|
12
|
+
# Author:: Daniel Tralamazza
|
13
|
+
# License:: {MIT # License.}[http://www.opensource.org/licenses/mit-license.php]
|
7
14
|
|
8
15
|
require 'thread'
|
9
16
|
|
@@ -1,17 +1,22 @@
|
|
1
|
-
#
|
2
|
-
#
|
1
|
+
# = Synopsis
|
2
|
+
# A bounded thread pool
|
3
3
|
#
|
4
|
-
#
|
4
|
+
# = Description
|
5
|
+
# This threadpool pre allocates _N_ threads to serve .spawn calls.
|
6
|
+
# By default workers are not killed if an exception is thrown, you can
|
7
|
+
# change this behavior by setting +kill_worker_on_exception+.
|
5
8
|
#
|
6
|
-
# Usage
|
9
|
+
# = Usage
|
10
|
+
# tpool = ThreadTools::ThreadPool.new(3)
|
11
|
+
# 12.times do |i|</tt>
|
12
|
+
# tpool.spawn(i, "hi") {|ti, ts|
|
13
|
+
# puts "#{Thread.current} (#{ti}) says #{ts}\n"
|
14
|
+
# }
|
15
|
+
# end
|
16
|
+
# tpool.shutdown
|
7
17
|
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
# tpool.spawn(i, "hi") {|ti, ts|
|
11
|
-
# puts "#{Thread.current} (#{ti}) says #{ts}\n"
|
12
|
-
# }
|
13
|
-
# end
|
14
|
-
# tpool.shutdown
|
18
|
+
# Author:: Daniel Tralamazza
|
19
|
+
# License:: {MIT # License.}[http://www.opensource.org/licenses/mit-license.php]
|
15
20
|
|
16
21
|
|
17
22
|
require 'thread'
|
@@ -28,7 +33,7 @@ module ThreadTools
|
|
28
33
|
# if set to true a new worker is created if the pool is empty
|
29
34
|
attr_accessor :create_on_spawn
|
30
35
|
|
31
|
-
# _size should be at least 1
|
36
|
+
# *_size* should be at least 1, *_thr_group* (optional) thread group
|
32
37
|
def initialize(_size, _thr_group = nil)
|
33
38
|
@kill_worker_on_exception = false
|
34
39
|
@size = 0
|
@@ -91,7 +96,7 @@ module ThreadTools
|
|
91
96
|
thr
|
92
97
|
end
|
93
98
|
|
94
|
-
def shutdown
|
99
|
+
def shutdown(_sync = true)
|
95
100
|
thr = nil
|
96
101
|
while !@pool.empty? do
|
97
102
|
@pool_mtx.synchronize do
|
@@ -100,7 +105,9 @@ module ThreadTools
|
|
100
105
|
thr[:jobs].clear # clear any pending job
|
101
106
|
thr[:jobs] << nil # queue a nil job
|
102
107
|
thr[:sem].release
|
103
|
-
|
108
|
+
if (_sync)
|
109
|
+
thr.join # wait here for the thread to die
|
110
|
+
end
|
104
111
|
end
|
105
112
|
end
|
106
113
|
end
|
data/test/test_debugmutex.rb
CHANGED
data/test/test_semaphore.rb
CHANGED
data/thread_tools.gemspec
CHANGED