You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: doc/channel.md
+7-7Lines changed: 7 additions & 7 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -57,7 +57,7 @@ msg = messages.take
57
57
puts msg
58
58
```
59
59
60
-
By default, channels are *unbuffered*, meaning that they have a size of zero and only accept puts and takes when both a putting and a taking thread are available. If a `put` is started when there is no taker thread the call will block. As soon as another thread calls `take` the exchange will occur and both calls will return on their respective threads. Similarly, is a `take` is started when there is no putting thread the call will block until another thread calls `put`.
60
+
By default, channels are *unbuffered*, meaning that they have a capacity of zero and only accept puts and takes when both a putting and a taking thread are available. If a `put` is started when there is no taker thread the call will block. As soon as another thread calls `take` the exchange will occur and both calls will return on their respective threads. Similarly, is a `take` is started when there is no putting thread the call will block until another thread calls `put`.
61
61
62
62
The following, slightly more complex example, concurrently sums two different halves of a list then combines the results. It uses an unbuffered channel to pass the results from the two goroutines back to the main thread. The main thread blocks on the two `take` calls until the worker goroutines are done. This example also uses the convenience aliases {#<<} and {#~}. Since channels in Go are part of the language, channel operations are performed using special channel operators rather than functions. These operators help clearly indicate that channel operations are being performed. The operator overloads `<<` for `put` and `~` for `take` help reinforce this idea in Ruby.
63
63
@@ -80,12 +80,12 @@ puts [x, y, x+y].join(' ')
80
80
81
81
## Channel Buffering
82
82
83
-
One common channel variation is a *buffered* channel. A buffered channel has a finite number of slots in the buffer which can be filled. Putting threads can put values into the channel even if there is no taking threads, up to the point where the buffer is filled. Once a buffer becomes full the normal blocking behavior resumes. A buffered channel is created by giving a `:size` option on channel creation:
83
+
One common channel variation is a *buffered* channel. A buffered channel has a finite number of slots in the buffer which can be filled. Putting threads can put values into the channel even if there is no taking threads, up to the point where the buffer is filled. Once a buffer becomes full the normal blocking behavior resumes. A buffered channel is created by giving a `:capacity` option on channel creation:
84
84
85
85
The following example creates a buffered channel with two slots. It then makes two `put` calls, adding values to the channel. These calls do not block because the buffer has room. Were a third `put` call to be made before an `take` calls, the third `put` would block.
86
86
87
87
```ruby
88
-
ch =Concurrent::Channel.new(size:2)
88
+
ch =Concurrent::Channel.new(capacity:2)
89
89
ch <<1
90
90
ch <<2
91
91
@@ -95,7 +95,7 @@ puts ~ch
95
95
96
96
## Channel Synchronization
97
97
98
-
The main purpose of channels is to synchronize operations across goroutines. One common pattern for this is to created a `size: 1` buffered channel which is used to signal that work is complete. The following example calls a `worker` function on a goroutine and passes it a "done" channel. The main thread then calls `take` on the "done" channel and blocks until signaled.
98
+
The main purpose of channels is to synchronize operations across goroutines. One common pattern for this is to created a `capacity: 1` buffered channel which is used to signal that work is complete. The following example calls a `worker` function on a goroutine and passes it a "done" channel. The main thread then calls `take` on the "done" channel and blocks until signaled.
99
99
100
100
```ruby
101
101
defworker(done_channel)
@@ -106,7 +106,7 @@ def worker(done_channel)
106
106
done_channel <<true
107
107
end
108
108
109
-
done =Concurrent::Channel.new(size:1)
109
+
done =Concurrent::Channel.new(capacity:1)
110
110
Concurrent::Channel.go{ worker(done) }
111
111
112
112
~done # block until signaled
@@ -176,7 +176,7 @@ fibonacci(c, quit)
176
176
177
177
## Closing and Iterating Over Channels
178
178
179
-
Newly created channels are in an "open" state. Open channels can receive values via `put` operations. When a program is done with a channel it can be closed by calling the {#close} method. Once a channel is closed it will no longer allow values to be `put`. If the channel is buffered and values are in the buffer when the channel is closed, the remaining values can still be removed via `take` operations.
179
+
Newly created channels are in an "open" state. Open channels can receive values via `put` operations. When a program is done with a channel it can be closed by calling the `#close` method. Once a channel is closed it will no longer allow values to be `put`. If the channel is buffered and values are in the buffer when the channel is closed, the remaining values can still be removed via `take` operations.
180
180
181
181
The `Channel` class implements an {#each} method which can be used to retrieve successive values from the channel. The `each` method is a blocking method. When the channel is open and there are no values in the buffer, `each` will block until a new item is `put`. The `each` method will not exit until the channel is closed.
182
182
@@ -192,7 +192,7 @@ def fibonacci(n, c)
192
192
c.close
193
193
end
194
194
195
-
chan =Concurrent::Channel.new(size:10)
195
+
chan =Concurrent::Channel.new(capacity:10)
196
196
Concurrent::Channel.go { fibonacci(chan.capacity, c) }
Copy file name to clipboardExpand all lines: doc/synchronization.md
+13-13Lines changed: 13 additions & 13 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -7,7 +7,7 @@
7
7
Provides common parent for all objects which need to be synchronized or be using other synchronization tools. It provides:
8
8
9
9
- Synchronized block
10
-
- Methods for waiting and signaling
10
+
- Methods for waiting and signaling
11
11
- Volatile fields
12
12
- Ensure visibility of final fields
13
13
- Fields with CAS operations
@@ -49,7 +49,7 @@ private
49
49
defns_compute
50
50
ns_compute_reduce ns_compute_map
51
51
end
52
-
```
52
+
```
53
53
where `compute` defines how is it synchronized and `ns_compute` handles the behavior (in this case the computation). `ns_` methods should only call other `ns_` methods or `pr_` methods. They can call normal methods on other objects, but that should be done with care (better to avoid) because the thread escapes this object while the lock is still held, which can lead to deadlock. That's why the `report` method is called in `compute` and not in `ns_compute`.
54
54
55
55
`pr_` methods are pure functions they can be used in and outside of synchronized blocks.
@@ -60,16 +60,16 @@ Sometimes while already inside the synchronized block some condition is not met.
All methods have to be called inside synchronized block.
69
69
70
70
## Volatile fields
71
71
72
-
`Synchronization::Object` can have volatile fields (Java semantic). They are defined by `attr_volatile :field_name`. `attr_volatile` defines reader and writer with the `field_name`. Any write is always immediately visible for any subsequent reads of the same field.
72
+
`Synchronization::Object` can have volatile fields (Java semantic). They are defined by `attr_volatile :field_name`. `attr_volatile` defines reader and writer with the `field_name`. Any write is always immediately visible for any subsequent reads of the same field.
73
73
74
74
## Ensure visibility of final fields
75
75
@@ -83,7 +83,7 @@ class AbstractPromise < Synchronization::Object
83
83
ensure_ivar_visibility!
84
84
end
85
85
# ...
86
-
end
86
+
end
87
87
```
88
88
89
89
### Naming conventions
@@ -112,10 +112,10 @@ class Event < Synchronization::Object
112
112
self
113
113
end
114
114
# ...
115
-
end
115
+
end
116
116
```
117
117
118
-
Operations on `@Touched` field have volatile semantic.
118
+
Operations on `@Touched` field have volatile semantic.
119
119
120
120
## Memory model
121
121
@@ -125,7 +125,7 @@ When writing libraries in `concurrent-ruby` we are reasoning based on following
125
125
126
126
The memory model is constructed based on our best effort and knowledge of the 3 main Ruby implementations (CRuby, JRuby, Rubinius). When considering certain aspect we always choose the weakest guarantee (e.g. local variable updates are always visible in CRuby but not in JRuby, so in this case JRuby behavior is picked). If some Ruby behavior is omitted here it is considered unsafe for use in parallel environment (Reasons may be lack of information, or difficulty of verification).
127
127
128
-
This takes in account following implementations:
128
+
This takes in account following implementations:
129
129
130
130
- CRuby 1.9 - 2.2 (no differences found)
131
131
- JRuby 1.7
@@ -139,10 +139,10 @@ We are interested in following behaviors:
139
139
140
140
### Variables
141
141
142
-
-**Local variables** - atomic assignment (only Integer and Object), non-volatile.
142
+
-**Local variables** - atomic assignment (only Integer and Object), non-volatile.
143
143
- Consequence: a lambda defined on `thread1` executing on `thread2` may not see updated values in local variables captured in its closure.
144
144
- Reason: local variables are non-volatile on Jruby and Rubinius.
145
-
-**Instance variables** - atomic assignment (only Integer and Object), non-volatile.
145
+
-**Instance variables** - atomic assignment (only Integer and Object), non-volatile.
146
146
- Consequence: Different thread may see old values; different thread may see not fully-initialized object.
147
147
- Reason: local variables are non-volatile on Jruby and Rubinius.
0 commit comments