multiprocessing 0.0.1 → 0.0.2
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.
- checksums.yaml +7 -0
- data/.gitignore +3 -1
- data/.yardopts +4 -0
- data/README.ja.md +121 -0
- data/README.md +85 -91
- data/Rakefile +24 -1
- data/lib/multiprocessing.rb +41 -1
- data/lib/multiprocessing/conditionvariable.rb +82 -60
- data/lib/multiprocessing/externalobject.rb +5 -3
- data/lib/multiprocessing/mutex.rb +126 -96
- data/lib/multiprocessing/processerror.rb +5 -0
- data/lib/multiprocessing/queue.rb +95 -27
- data/lib/multiprocessing/semaphore.rb +78 -27
- data/lib/multiprocessing/version.rb +12 -1
- data/spec/multiprocessing/conditionvariable_spec.rb +206 -0
- data/spec/multiprocessing/mutex_spec.rb +468 -74
- data/spec/multiprocessing/queue_spec.rb +341 -97
- data/spec/multiprocessing/semaphore_spec.rb +136 -33
- data/spec/spec_helper.rb +15 -1
- metadata +11 -12
- data/lib/multiprocessing/process.rb +0 -43
- data/spec/multiprocessing/process_spec.rb +0 -51
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: a816b2236a62749e3a5a34d2aa1f4786300c3ef7
|
4
|
+
data.tar.gz: 7a5291e800ff6077642ecd792fe9a65f339afa99
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a99c37e3fd90b73b7520114d36339c544691a84c55c4267c24caae479ce6399a5631087bb7e0ce931d7b4374db7e06be19d2fd500da4bc191ca0bd8be27088c5
|
7
|
+
data.tar.gz: d03ef0421e9f3014bae846bcaa00e9394d8ee3bf696cfa1d7376feae612dd6e2ca317262070e3fa5ab579b445f2d23c3bf9501c4456eab96770f4ec58a3c4a05
|
data/.gitignore
CHANGED
data/.yardopts
ADDED
data/README.ja.md
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
MultiProcessing
|
2
|
+
====================
|
3
|
+
|
4
|
+
MultiProcessingはRubyにおいてプロセス間同期とプロセス間通信の機能を提供します(することを目指しています).
|
5
|
+
各クラスはRubyの標準添付ライブラリthreadで提供されているクラスのような動作をすることを目指しています.
|
6
|
+
|
7
|
+
MultiProcessing includes classes for inter-process synchronization and communication.
|
8
|
+
The classes can be used like ones in ruby standard library for thread.
|
9
|
+
|
10
|
+
現状で使用できるクラスは以下です.
|
11
|
+
各クラスはMultiProcessingモジュールの下に作成されています.
|
12
|
+
|
13
|
+
* Mutex
|
14
|
+
* ConditionVariable
|
15
|
+
* Semaphore
|
16
|
+
* Queue
|
17
|
+
* ExternalObject
|
18
|
+
|
19
|
+
また,IO.named\_pipe が追加されます
|
20
|
+
|
21
|
+
いずれのクラスもプロセス間通信にパイプ(IO.pipe)を使用しています.
|
22
|
+
また,複数のプロセスで1つの同期オブジェクトを共有するためにforkを使用する事を想定しているため,
|
23
|
+
Unix系OSのみでのみ使用する事ができます.
|
24
|
+
|
25
|
+
(Windowsするためには,名前付き共有セマフォなどの同期機能を使用する必要がありそうですね・・・)
|
26
|
+
|
27
|
+
Install
|
28
|
+
----------------
|
29
|
+
|
30
|
+
gem install multiprocessing
|
31
|
+
|
32
|
+
Mutex
|
33
|
+
----------------
|
34
|
+
|
35
|
+
標準添付ライブラリthreadのMutexと同様の使い方をします.
|
36
|
+
|
37
|
+
m = MultiProcessing::Mutex.new
|
38
|
+
fork do
|
39
|
+
m.synchronize do
|
40
|
+
# some critical work
|
41
|
+
end
|
42
|
+
end
|
43
|
+
m.synchronize do
|
44
|
+
# come critical work
|
45
|
+
end
|
46
|
+
Process.waitall
|
47
|
+
|
48
|
+
lockした後unlockする前にforkすると(synchronize中でforkした場合も)そのクリティカルセクションは並列に動作してしまうので注意してください.
|
49
|
+
(forkしたときに子プロセスでは子スレッドが全て殺されるため,別のスレッドでforkすれば問題ないと思います.)
|
50
|
+
|
51
|
+
ConditionVariable
|
52
|
+
----------------
|
53
|
+
|
54
|
+
標準添付ライブラリthreadのConditionVariableと同じ使い方をします.
|
55
|
+
|
56
|
+
m = MultiProcessing::Mutex.new
|
57
|
+
cond = MultiProcessing::ConditionVariable.new
|
58
|
+
fork do
|
59
|
+
m.synchronize do
|
60
|
+
cond.wait(m)
|
61
|
+
# something to do
|
62
|
+
end
|
63
|
+
end
|
64
|
+
sleep 1
|
65
|
+
# on condition changed
|
66
|
+
cond.signal
|
67
|
+
Process.waitall
|
68
|
+
|
69
|
+
Semaphore
|
70
|
+
----------------
|
71
|
+
|
72
|
+
Semaphoreは標準添付ライブラリに含まれていませんが作りました.
|
73
|
+
|
74
|
+
s = MultiProcessing::Semaphore.new 2
|
75
|
+
|
76
|
+
コンストラクタにリソース量の初期値を与えてください.
|
77
|
+
Pでリソースのロック,Vで解放をします.
|
78
|
+
|
79
|
+
Pはlock,Vはunlockという名前のエイリアスが用意してあります.
|
80
|
+
|
81
|
+
Queue
|
82
|
+
----------------
|
83
|
+
|
84
|
+
Queueも標準threadライブラリのQueueと同様の使い方をします.
|
85
|
+
|
86
|
+
q = MultiProcessing::Quque.new
|
87
|
+
fork do
|
88
|
+
q.push :nyan
|
89
|
+
q.close.join_thread
|
90
|
+
end
|
91
|
+
p q.pop
|
92
|
+
|
93
|
+
プロセス間の通信にはパイプを使っています.Queue#pushをすると,パイプにデータを書き込むバックグラウンドスレッドが起動します(pythonのmultiprocessingを参考にしました).
|
94
|
+
プロセスが終了する際,バックグラウンドスレッドがパイプにデータを書き込み終わるまで待たないと,Queueが書き込みMutexをロックしたままになる場合があります.
|
95
|
+
終了時は
|
96
|
+
|
97
|
+
q.close.join_thread
|
98
|
+
|
99
|
+
として,書き込みスレッドの終了を待ってください.close後にキューにデータをpushすると例外が発生します.
|
100
|
+
|
101
|
+
オブジェクトのシリアライズにMarshal.dumpを使用しているので,Marshal.dumpできないオブジェクトをpushできません.
|
102
|
+
|
103
|
+
その他
|
104
|
+
----------------
|
105
|
+
|
106
|
+
### 関係ありそうなライブラリ
|
107
|
+
|
108
|
+
* https://github.com/pmahoney/process_shared
|
109
|
+
|
110
|
+
### TODO
|
111
|
+
|
112
|
+
* ExternalObject, IO.named\_pipe のSpecを書く
|
113
|
+
* ドキュメントを書く
|
114
|
+
|
115
|
+
ライセンス
|
116
|
+
----------------
|
117
|
+
|
118
|
+
Author: clicube
|
119
|
+
|
120
|
+
MIT License
|
121
|
+
|
data/README.md
CHANGED
@@ -1,130 +1,124 @@
|
|
1
|
-
MultiProcessing
|
2
|
-
====================
|
1
|
+
# MultiProcessing #
|
3
2
|
|
4
|
-
MultiProcessing
|
5
|
-
|
3
|
+
MultiProcessing provides classes for
|
4
|
+
inter-process synchronization and communication in Ruby.
|
6
5
|
|
7
|
-
|
8
|
-
The classes can be used like ones in ruby standard library for thread.
|
6
|
+
These classes can be used like ones in Ruby standard library for multi threading.
|
9
7
|
|
10
|
-
|
11
|
-
|
8
|
+
To realize communicating across processes,
|
9
|
+
MultiProcessing uses pipes (IO.pipe).
|
10
|
+
You have to use #fork to create process which accesses synchonizing/communication object.
|
11
|
+
For this reason, MultiProcessing can be used only on Unix or Linux.
|
12
|
+
|
13
|
+
## Install ##
|
14
|
+
|
15
|
+
gem install multiprocessing
|
16
|
+
|
17
|
+
## Provided Classes ##
|
12
18
|
|
13
19
|
* Mutex
|
14
20
|
* ConditionVariable
|
15
21
|
* Semaphore
|
16
22
|
* Queue
|
17
|
-
*
|
18
|
-
* ExternalObject
|
23
|
+
* (ExternalObject: under development)
|
19
24
|
|
20
|
-
|
25
|
+
In addition, IO.name\_pipe is added.
|
21
26
|
|
22
|
-
|
23
|
-
また,複数のプロセスで1つの同期オブジェクトを共有するためにforkを使用する事を想定しているため,
|
24
|
-
Unix系OSのみでのみ使用する事ができます.
|
27
|
+
## Mutex ##
|
25
28
|
|
26
|
-
|
29
|
+
Process version of Mutex.
|
30
|
+
It can be used like ::Mutex in Ruby standard library.
|
27
31
|
|
28
|
-
|
29
|
-
----------------
|
32
|
+
Example:
|
30
33
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
34
|
+
require 'multiprocessing'
|
35
|
+
|
36
|
+
mutex = MultiProcessing::Mutex.new
|
37
|
+
3.times do
|
38
|
+
fork do
|
39
|
+
mutex.synchronize do
|
40
|
+
# critical section
|
41
|
+
puts Process.pid
|
42
|
+
sleep 1
|
43
|
+
end
|
37
44
|
end
|
38
45
|
end
|
39
|
-
m.synchronize do
|
40
|
-
# come critical work
|
41
|
-
end
|
42
46
|
Process.waitall
|
47
|
+
# => prints 3 pids of forked process in 1 sec interval
|
48
|
+
|
49
|
+
Note: Do not fork in critical section.
|
43
50
|
|
44
|
-
|
45
|
-
(forkしたときに子プロセスでは子スレッドが全て殺されるため,別のスレッドでforkすれば問題ないと思います.)
|
51
|
+
## ConditionVariable ##
|
46
52
|
|
47
|
-
ConditionVariable
|
48
|
-
|
53
|
+
Process version of ConditionVariable.
|
54
|
+
It can be used like ::ConditionVariable in Ruby standard library.
|
49
55
|
|
50
|
-
|
56
|
+
Example:
|
51
57
|
|
52
|
-
|
53
|
-
|
58
|
+
require 'multiprocessing'
|
59
|
+
|
60
|
+
m = MultiProcessing::Mutex.new
|
61
|
+
cond = MultiProcessing::ConditionVariable.new
|
62
|
+
3.times do
|
54
63
|
fork do
|
55
64
|
m.synchronize do
|
65
|
+
puts "waiting pid:#{Process.pid}"
|
56
66
|
cond.wait(m)
|
57
|
-
|
67
|
+
puts "restarted pid:#{Process.pid}"
|
58
68
|
end
|
59
69
|
end
|
60
|
-
|
61
|
-
#
|
62
|
-
|
63
|
-
|
70
|
+
end
|
71
|
+
sleep 0.1 # => 3 processes get waiting a signal
|
72
|
+
cond.signal # => One process restarts
|
73
|
+
cond.broadcast # => Remaining 2 process restart
|
74
|
+
Process.waitall
|
75
|
+
|
76
|
+
|
77
|
+
## Semaphore ##
|
64
78
|
|
65
|
-
Semaphore
|
66
|
-
|
79
|
+
Semaphore is like Mutex but it can manage multiple resources.
|
80
|
+
It is initialized with initiali number of resources.
|
81
|
+
It can be release from the thread or process which didn't lock the semaphore.
|
67
82
|
|
68
|
-
|
83
|
+
Example:
|
69
84
|
|
85
|
+
require 'multiprocessing'
|
86
|
+
|
70
87
|
s = MultiProcessing::Semaphore.new 2
|
88
|
+
3.times do
|
89
|
+
fork do
|
90
|
+
s.synchronize do
|
91
|
+
puts "pid: #{Process.pid}"
|
92
|
+
sleep 1
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
Process.waitall
|
97
|
+
# => two processes prints its pid immediately
|
98
|
+
# but the other does late.
|
71
99
|
|
72
|
-
|
73
|
-
Pでリソースのロック,Vで解放をします.
|
100
|
+
## Queue ##
|
74
101
|
|
75
|
-
|
102
|
+
Process version of Queue.
|
103
|
+
It provides away to communication between processes.
|
104
|
+
It can be used like ::Queue in Ruby standard library.
|
76
105
|
|
77
|
-
Queue
|
78
|
-
|
106
|
+
Queue usees pipes to communicate with other processes.
|
107
|
+
Queue#push} starts background thread ti write data to the pipe.
|
108
|
+
Avoiding to exit process before writing to the pipe,
|
109
|
+
use Queue#close and Queue#join\_thread.
|
110
|
+
Queue#join\_thread waits until all data is written to the pipe.
|
79
111
|
|
80
|
-
|
112
|
+
Example:
|
81
113
|
|
82
|
-
|
114
|
+
require 'multiprocessing'
|
115
|
+
|
116
|
+
q = MultiProcessing::Queue.new
|
83
117
|
fork do
|
84
118
|
q.push :nyan
|
119
|
+
q.push :wan
|
85
120
|
q.close.join_thread
|
86
121
|
end
|
87
|
-
|
88
|
-
|
89
|
-
プロセス間の通信にはパイプを使っています.Queue#pushをすると,パイプにデータを書き込むバックグラウンドスレッドが起動します(pythonのmultiprocessingを参考にしました).
|
90
|
-
プロセスが終了する際,バックグラウンドスレッドがパイプにデータを書き込み終わるまで待たないと,Queueが書き込みMutexをロックしたままになる場合があります.
|
91
|
-
終了時は
|
92
|
-
|
93
|
-
q.close.join_thread
|
94
|
-
|
95
|
-
として,書き込みスレッドの終了を待ってください.close後にキューにデータをpushすると例外が発生します.
|
96
|
-
|
97
|
-
オブジェクトのシリアライズにMarshal.dumpを使用しているので,Marshal.dumpできないオブジェクトをpushできません.
|
98
|
-
|
99
|
-
Process
|
100
|
-
----------------
|
101
|
-
|
102
|
-
標準のProcessモジュールは
|
103
|
-
|
104
|
-
>Process がプロセスを表現するクラスではなく、プロセスに対する操作 をまとめたモジュールであることに注意してください。
|
105
|
-
|
106
|
-
とのことなので,プロセスを表現するっぽいクラスを作ってみました.
|
107
|
-
|
108
|
-
p = MultiProcessing::Process.new { # something to do }
|
109
|
-
p.join
|
110
|
-
|
111
|
-
とかできます.
|
112
|
-
|
113
|
-
その他
|
114
|
-
----------------
|
115
|
-
|
116
|
-
### 関係ありそうなライブラリ
|
117
|
-
|
118
|
-
* https://github.com/pmahoney/process_shared
|
119
|
-
|
120
|
-
### TODO
|
121
|
-
|
122
|
-
* ConditionVariable, ExternalObject, IO.named\_pipe のSpecを書く
|
123
|
-
|
124
|
-
ライセンス
|
125
|
-
----------------
|
126
|
-
|
127
|
-
Author: clicube
|
128
|
-
|
129
|
-
MIT License
|
122
|
+
q.pop # => :nyan
|
123
|
+
q.pop # => :wan
|
130
124
|
|
data/Rakefile
CHANGED
@@ -1 +1,24 @@
|
|
1
|
-
require
|
1
|
+
require 'bundler/gem_tasks'
|
2
|
+
|
3
|
+
task :default => :spec
|
4
|
+
|
5
|
+
#### RSpec Task####
|
6
|
+
|
7
|
+
require 'rspec/core/rake_task'
|
8
|
+
|
9
|
+
RSpec::Core::RakeTask.new(:spec, :name) do |t,task_args|
|
10
|
+
t.pattern = "spec/**/#{task_args[:name]}_spec.rb" if task_args[:name]
|
11
|
+
t.rspec_opts = "--color --order rand"
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
#### Yard Task ####
|
16
|
+
|
17
|
+
require 'yard'
|
18
|
+
require 'yard/rake/yardoc_task'
|
19
|
+
|
20
|
+
YARD::Rake::YardocTask.new("yard") do |t|
|
21
|
+
t.options = ["--no-stats"]
|
22
|
+
t.after = ->{ YARD::CLI::Stats.run("--list-undoc") }
|
23
|
+
end
|
24
|
+
|
data/lib/multiprocessing.rb
CHANGED
@@ -2,7 +2,47 @@ require File.expand_path(File.dirname(__FILE__) + '/multiprocessing/mutex')
|
|
2
2
|
require File.expand_path(File.dirname(__FILE__) + '/multiprocessing/conditionvariable')
|
3
3
|
require File.expand_path(File.dirname(__FILE__) + '/multiprocessing/semaphore')
|
4
4
|
require File.expand_path(File.dirname(__FILE__) + '/multiprocessing/queue')
|
5
|
-
require File.expand_path(File.dirname(__FILE__) + '/multiprocessing/process')
|
6
5
|
require File.expand_path(File.dirname(__FILE__) + '/multiprocessing/namedpipe')
|
7
6
|
require File.expand_path(File.dirname(__FILE__) + '/multiprocessing/externalobject')
|
8
7
|
|
8
|
+
##
|
9
|
+
#
|
10
|
+
# MultiProcessing provides classes for
|
11
|
+
# inter-process synchronization and communication in Ruby.
|
12
|
+
#
|
13
|
+
# These classes can be used like ones in Ruby standard library for multi threading.
|
14
|
+
#
|
15
|
+
# To realize communitation across processes, MultiProcessing uses pipe (IO.pipe).
|
16
|
+
# You have to use fork to create multiple processes
|
17
|
+
# which accesses synchronizing/communication object.
|
18
|
+
# For this reason, MultiProcessing can be used only on Unix or Linux.
|
19
|
+
#
|
20
|
+
#
|
21
|
+
module MultiProcessing
|
22
|
+
|
23
|
+
# documentation is at below
|
24
|
+
if Thread.respond_to?(:handle_interrupt)
|
25
|
+
def try_handle_interrupt *args, &block
|
26
|
+
Thread.handle_interrupt *args, &block
|
27
|
+
end
|
28
|
+
else
|
29
|
+
def try_handle_interrupt *args
|
30
|
+
yield
|
31
|
+
end
|
32
|
+
end
|
33
|
+
module_function :try_handle_interrupt
|
34
|
+
##
|
35
|
+
#
|
36
|
+
# @!method try_handle_interrupt *args
|
37
|
+
# @scope class
|
38
|
+
#
|
39
|
+
# If Thread has handle_interrupt (Ruby 2.0.0 or later), call it with given arguments and block.
|
40
|
+
# If not, simply yield passed block
|
41
|
+
#
|
42
|
+
# @param [Array<Object>] args arguments to give Thread.handle_interrupt
|
43
|
+
# @return [Object] returned value of the block
|
44
|
+
#
|
45
|
+
##
|
46
|
+
|
47
|
+
end
|
48
|
+
|
@@ -2,6 +2,33 @@ require File.expand_path(File.dirname(__FILE__) + '/processerror')
|
|
2
2
|
require File.expand_path(File.dirname(__FILE__) + '/mutex')
|
3
3
|
|
4
4
|
module MultiProcessing
|
5
|
+
|
6
|
+
##
|
7
|
+
#
|
8
|
+
# Process version of ConditionVariable
|
9
|
+
# This can be used like ::ConditionVariable in Ruby standard library.
|
10
|
+
#
|
11
|
+
# Note that ConditionVariable uses 2 pipes.
|
12
|
+
#
|
13
|
+
# @example
|
14
|
+
# require 'multiprocessing'
|
15
|
+
#
|
16
|
+
# m = MultiProcessing::Mutex.new
|
17
|
+
# cond = MultiProcessing::ConditionVariable.new
|
18
|
+
# 3.times do
|
19
|
+
# fork do
|
20
|
+
# m.synchronize do
|
21
|
+
# puts "waiting pid:#{Process.pid}"
|
22
|
+
# cond.wait(m)
|
23
|
+
# puts "restarted pid:#{Process.pid}"
|
24
|
+
# end
|
25
|
+
# end
|
26
|
+
# end
|
27
|
+
# sleep 0.1 # => 3 processes get waiting a signal
|
28
|
+
# cond.signal # => One process restarts
|
29
|
+
# cond.broadcast # => Remaining 2 process restart
|
30
|
+
# Process.waitall
|
31
|
+
#
|
5
32
|
class ConditionVariable
|
6
33
|
|
7
34
|
def initialize
|
@@ -9,76 +36,71 @@ module MultiProcessing
|
|
9
36
|
@signal_pout,@signal_pin = IO.pipe
|
10
37
|
end
|
11
38
|
|
39
|
+
##
|
40
|
+
#
|
41
|
+
# Wakes up all threads waiting for this lock.
|
42
|
+
#
|
43
|
+
# @return [Fixnum] Number of threads waked up
|
44
|
+
#
|
12
45
|
def broadcast
|
13
|
-
|
46
|
+
n = 0
|
47
|
+
while(signal)
|
48
|
+
n += 1
|
49
|
+
end
|
50
|
+
return n
|
14
51
|
end
|
15
52
|
|
53
|
+
##
|
54
|
+
#
|
55
|
+
# Wakes up one of threads waiting for this lock.
|
56
|
+
#
|
57
|
+
# @note An order of waking up is indefinite.
|
58
|
+
#
|
59
|
+
# @return [Boolean] Returns true if wakes up. Returns false if no threads were waiting.
|
60
|
+
#
|
16
61
|
def signal
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
62
|
+
MultiProcessing.try_handle_interrupt(RuntimeError => :never) do
|
63
|
+
begin
|
64
|
+
@waiting_pout.read_nonblock 1
|
65
|
+
@signal_pin.syswrite 1
|
66
|
+
return true
|
67
|
+
rescue Errno::EAGAIN
|
68
|
+
return false
|
69
|
+
end
|
25
70
|
end
|
26
71
|
end
|
27
72
|
|
73
|
+
##
|
74
|
+
#
|
75
|
+
# Releases the lock held in mutex and waits, reacquires the lock on wakeup.
|
76
|
+
#
|
77
|
+
# @param [Mutex] mutex An instance of MultiProcessing::Mutex. It must be locked.
|
78
|
+
# @return [ConditionVariable] itself
|
79
|
+
# @note Do not pass an instance of ::Mutex. Pass an instance of MultiProcessing::Mutex.
|
80
|
+
#
|
81
|
+
# @raise [TypeError]
|
82
|
+
# @raise [ArgumentError]
|
83
|
+
#
|
28
84
|
def wait(mutex)
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
85
|
+
MultiProcessing.try_handle_interrupt(RuntimeError => :never) do
|
86
|
+
raise TypeError.new("mutex must be instance of MultiProcessing::Mutex") if mutex.class != MultiProcessing::Mutex
|
87
|
+
raise ArgumentError.new("mutex must be locked") unless mutex.locked?
|
88
|
+
@waiting_pin.syswrite 1
|
89
|
+
mutex.unlock
|
90
|
+
begin
|
91
|
+
MultiProcessing.try_handle_interrupt(RuntimeError => :on_blocking) do
|
92
|
+
@signal_pout.readpartial 1
|
93
|
+
end
|
94
|
+
rescue Exception => e
|
95
|
+
@waiting_pout.readpartial 1
|
96
|
+
raise e
|
97
|
+
ensure
|
98
|
+
mutex.lock
|
99
|
+
end
|
100
|
+
self
|
101
|
+
end
|
37
102
|
end
|
38
103
|
|
39
104
|
end
|
40
105
|
end
|
41
106
|
|
42
|
-
if __FILE__ == $0
|
43
|
-
|
44
|
-
m = MultiProcessing::Mutex.new
|
45
|
-
cond = MultiProcessing::ConditionVariable.new
|
46
|
-
fork do
|
47
|
-
m.synchronize do
|
48
|
-
sleep 1
|
49
|
-
puts "waiting p1"
|
50
|
-
cond.wait(m)
|
51
|
-
puts "restarted p1"
|
52
|
-
sleep 1
|
53
|
-
puts "end p1"
|
54
|
-
end
|
55
|
-
end
|
56
|
-
fork do
|
57
|
-
m.synchronize do
|
58
|
-
sleep 1
|
59
|
-
puts "waiting p2"
|
60
|
-
cond.wait(m)
|
61
|
-
puts "restarted p2"
|
62
|
-
sleep 1
|
63
|
-
puts "end p2"
|
64
|
-
end
|
65
|
-
end
|
66
|
-
fork do
|
67
|
-
m.synchronize do
|
68
|
-
sleep 1
|
69
|
-
puts "waiting p3"
|
70
|
-
cond.wait(m)
|
71
|
-
puts "restarted p3"
|
72
|
-
sleep 1
|
73
|
-
puts "end p3"
|
74
|
-
end
|
75
|
-
end
|
76
|
-
sleep 5
|
77
|
-
puts "cond signaling"
|
78
|
-
cond.signal
|
79
|
-
sleep 3
|
80
|
-
puts "cond broadcasting"
|
81
|
-
cond.broadcast
|
82
|
-
Process.waitall
|
83
|
-
end
|
84
|
-
|