/
TVar.html
644 lines (428 loc) · 29.2 KB
/
TVar.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>
Class: Concurrent::TVar
— Concurrent Ruby
</title>
<link rel="stylesheet" href="../css/style.css" type="text/css" charset="utf-8" />
<link rel="stylesheet" href="../css/common.css" type="text/css" charset="utf-8" />
<script type="text/javascript" charset="utf-8">
pathId = "Concurrent::TVar";
relpath = '../';
</script>
<script type="text/javascript" charset="utf-8" src="../js/jquery.js"></script>
<script type="text/javascript" charset="utf-8" src="../js/app.js"></script>
</head>
<body>
<div class="nav_wrap">
<iframe id="nav" src="../class_list.html?1"></iframe>
<div id="resizer"></div>
</div>
<div id="main" tabindex="-1">
<div id="header">
<div id="menu">
<a href="../_index.html">Index (T)</a> »
<span class='title'><span class='object_link'><a href="../Concurrent.html" title="Concurrent (module)">Concurrent</a></span></span>
»
<span class="title">TVar</span>
</div>
<div id="search">
<a class="full_list_link" id="class_list_link"
href="../class_list.html">
<svg width="24" height="24">
<rect x="0" y="4" width="24" height="4" rx="1" ry="1"></rect>
<rect x="0" y="12" width="24" height="4" rx="1" ry="1"></rect>
<rect x="0" y="20" width="24" height="4" rx="1" ry="1"></rect>
</svg>
</a>
</div>
<div class="clear"></div>
</div>
<div id="content"><h1>Class: Concurrent::TVar
</h1>
<div class="box_info">
<dl>
<dt>Inherits:</dt>
<dd>
<span class="inheritName"><span class='object_link'><a href="Synchronization/Object.html" title="Concurrent::Synchronization::Object (class)">Synchronization::Object</a></span></span>
<ul class="fullTree">
<li>Object</li>
<li class="next"><span class='object_link'><a href="Synchronization/Object.html" title="Concurrent::Synchronization::Object (class)">Synchronization::Object</a></span></li>
<li class="next">Concurrent::TVar</li>
</ul>
<a href="#" class="inheritanceTree">show all</a>
</dd>
</dl>
<dl>
<dt>Defined in:</dt>
<dd>lib/concurrent/tvar.rb</dd>
</dl>
</div>
<h2>Overview</h2><div class="docstring">
<div class="discussion">
<p>A <code>TVar</code> is a transactional variable - a single-element container that
is used as part of a transaction - see <code>Concurrent::atomically</code>.</p>
<h2>Thread-safe Variable Classes</h2>
<p>Each of the thread-safe variable classes is designed to solve a different
problem. In general:</p>
<ul>
<li><em><span class='object_link'><a href="Agent.html" title="Concurrent::Agent (class)">Agent</a></span>:</em> Shared, mutable variable providing independent,
uncoordinated, <em>asynchronous</em> change of individual values. Best used when
the value will undergo frequent, complex updates. Suitable when the result
of an update does not need to be known immediately.</li>
<li><em><span class='object_link'><a href="Atom.html" title="Concurrent::Atom (class)">Atom</a></span>:</em> Shared, mutable variable providing independent,
uncoordinated, <em>synchronous</em> change of individual values. Best used when
the value will undergo frequent reads but only occasional, though complex,
updates. Suitable when the result of an update must be known immediately.</li>
<li><em><span class='object_link'><a href="AtomicReference.html" title="Concurrent::AtomicReference (class)">AtomicReference</a></span>:</em> A simple object reference that can be
atomically. Updates are synchronous but fast. Best used when updates a
simple set operations. Not suitable when updates are complex.
<span class='object_link'><a href="AtomicBoolean.html" title="Concurrent::AtomicBoolean (class)">AtomicBoolean</a></span> and <span class='object_link'><a href="AtomicFixnum.html" title="Concurrent::AtomicFixnum (class)">AtomicFixnum</a></span> are similar
but optimized for the given data type.</li>
<li><em><span class='object_link'><a href="Exchanger.html" title="Concurrent::Exchanger (class)">Exchanger</a></span>:</em> Shared, stateless synchronization point. Used
when two or more threads need to exchange data. The threads will pair then
block on each other until the exchange is complete.</li>
<li><em><span class='object_link'><a href="MVar.html" title="Concurrent::MVar (class)">MVar</a></span>:</em> Shared synchronization point. Used when one thread
must give a value to another, which must take the value. The threads will
block on each other until the exchange is complete.</li>
<li><em><span class='object_link'><a href="ThreadLocalVar.html" title="Concurrent::ThreadLocalVar (class)">ThreadLocalVar</a></span>:</em> Shared, mutable, isolated variable which
holds a different value for each thread which has access. Often used as
an instance variable in objects which must maintain different state
for different threads.</li>
<li><em><span class='object_link'><a href="" title="Concurrent::TVar (class)">TVar</a></span>:</em> Shared, mutable variables which provide
<em>coordinated</em>, <em>synchronous</em>, change of <em>many</em> stated. Used when multiple
value must change together, in an all-or-nothing transaction.
<code>TVar</code> and <code>atomically</code> implement a software transactional memory. A <code>TVar</code> is a
single item container that always contains exactly one value. The <code>atomically</code>
method allows you to modify a set of <code>TVar</code> objects with the guarantee that all
of the updates are collectively atomic - they either all happen or none of them
do - consistent - a <code>TVar</code> will never enter an illegal state - and isolated -
atomic blocks never interfere with each other when they are running. You may
recognise these properties from database transactions.</p>
<p>There are some very important and unusual semantics that you must be aware of:</p>
<ul>
<li><p>Most importantly, the block that you pass to <code>atomically</code> may be executed more
than once. In most cases your code should be free of side-effects, except for
via <code>TVar</code>.</p></li>
<li><p>If an exception escapes an <code>atomically</code> block it will abort the transaction.</p></li>
<li><p>It is undefined behaviour to use <code>callcc</code> or <code>Fiber</code> with <code>atomically</code>.</p></li>
<li><p>If you create a new thread within an <code>atomically</code>, it will not be part of
the transaction. Creating a thread counts as a side-effect.</p></li>
</ul>
<p>We implement nested transactions by flattening.</p>
<p>We only support strong isolation if you use the API correctly. In order words,
we do not support strong isolation.</p>
<p>Our implementation uses a very simple two-phased locking with versioned locks
algorithm and lazy writes, as per [1]. In the future we will look at more
advanced algorithms, contention management and using existing Java
implementations when in JRuby.</p>
<p>See:</p>
<ol>
<li> T. Harris, J. Larus, and R. Rajwar. Transactional Memory. Morgan & Claypool, second edition, 2010.</li>
</ol>
<h2>Motivation</h2>
<p>Consider an application that transfers money between bank accounts. We want to
transfer money from one account to another. It is very important that we don't
lose any money! But it is also important that we can handle many account
transfers at the same time, so we run them concurrently, and probably also in
parallel.</p>
<p>This code shows us transferring ten pounds from one account to another.</p>
<pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_a'>a</span> <span class='op'>=</span> <span class='const'>BankAccount</span><span class='period'>.</span><span class='id identifier rubyid_new'>new</span><span class='lparen'>(</span><span class='int'>100_000</span><span class='rparen'>)</span>
<span class='id identifier rubyid_b'>b</span> <span class='op'>=</span> <span class='const'>BankAccount</span><span class='period'>.</span><span class='id identifier rubyid_new'>new</span><span class='lparen'>(</span><span class='int'>100</span><span class='rparen'>)</span>
<span class='id identifier rubyid_a'>a</span><span class='period'>.</span><span class='id identifier rubyid_value'>value</span> <span class='op'>-=</span> <span class='int'>10</span>
<span class='id identifier rubyid_b'>b</span><span class='period'>.</span><span class='id identifier rubyid_value'>value</span> <span class='op'>+=</span> <span class='int'>10</span>
</code></pre>
<p>Before we even start to talk about to talk about concurrency and parallelism, is
this code safe? What happens if after removing money from account a, we get an
exception? It's a slightly contrived example, but if the account totals were
very large, adding to them could involve the stack allocation of a <code>BigNum</code>, and
so could cause out of memory exceptions. In that case the money would have
disappeared from account a, but not appeared in account b. Disaster!</p>
<p>So what do we really need to do?</p>
<pre class="code ruby"><code class="ruby">a = BankAccount.new(100_000)
b = BankAccount.new(100)
original_a = a.value
a.value -= 10
begin
b.value += 10
rescue e =>
a.value = original_a
raise e
end
</code></pre>
<p>This rescues any exceptions raised when setting b and will roll back the change
we have already made to b. We'll keep this rescue code in mind, but we'll leave
it out of future examples for simplicity.</p>
<p>That might have made the code work when it only runs sequentially. Lets start to
consider some concurrency. It's obvious that we want to make the transfer of
money mutually exclusive with any other transfers - in order words it is a
critical section.</p>
<p>The usual solution to this would be to use a lock.</p>
<pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_lock'>lock</span><span class='period'>.</span><span class='id identifier rubyid_synchronize'>synchronize</span> <span class='kw'>do</span>
<span class='id identifier rubyid_a'>a</span><span class='period'>.</span><span class='id identifier rubyid_value'>value</span> <span class='op'>-=</span> <span class='int'>10</span>
<span class='id identifier rubyid_b'>b</span><span class='period'>.</span><span class='id identifier rubyid_value'>value</span> <span class='op'>+=</span> <span class='int'>10</span>
<span class='kw'>end</span>
</code></pre>
<p>That should work. Except we said we'd like these transfer to run concurrently,
and in parallel. With a single lock like that we'll only let one transfer take
place at a time. Perhaps we need more locks? We could have one per account:</p>
<pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_a'>a</span><span class='period'>.</span><span class='id identifier rubyid_lock'>lock</span><span class='period'>.</span><span class='id identifier rubyid_synchronize'>synchronize</span> <span class='kw'>do</span>
<span class='id identifier rubyid_b'>b</span><span class='period'>.</span><span class='id identifier rubyid_lock'>lock</span><span class='period'>.</span><span class='id identifier rubyid_synchronize'>synchronize</span> <span class='kw'>do</span>
<span class='id identifier rubyid_a'>a</span><span class='period'>.</span><span class='id identifier rubyid_value'>value</span> <span class='op'>-=</span> <span class='int'>10</span>
<span class='id identifier rubyid_b'>b</span><span class='period'>.</span><span class='id identifier rubyid_value'>value</span> <span class='op'>+=</span> <span class='int'>10</span>
<span class='kw'>end</span>
<span class='kw'>end</span>
</code></pre>
<p>However this is vulnerable to deadlock. If we tried to transfer from a to b, at
the same time as from b to a, it's possible that the first transfer locks a, the
second transfer locks b, and then they both sit there waiting forever to get the
other lock. Perhaps we can solve that by applying a total ordering to the locks
and always acquire them in the same order?</p>
<pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_locks_needed'>locks_needed</span> <span class='op'>=</span> <span class='lbracket'>[</span><span class='id identifier rubyid_a'>a</span><span class='period'>.</span><span class='id identifier rubyid_lock'>lock</span><span class='comma'>,</span> <span class='id identifier rubyid_b'>b</span><span class='period'>.</span><span class='id identifier rubyid_lock'>lock</span><span class='rbracket'>]</span>
<span class='id identifier rubyid_locks_in_order'>locks_in_order</span> <span class='op'>=</span> <span class='id identifier rubyid_locks_needed'>locks_needed</span><span class='period'>.</span><span class='id identifier rubyid_sort'>sort</span><span class='lbrace'>{</span> <span class='op'>|</span><span class='id identifier rubyid_x'>x</span><span class='comma'>,</span> <span class='id identifier rubyid_y'>y</span><span class='op'>|</span> <span class='id identifier rubyid_x'>x</span><span class='period'>.</span><span class='id identifier rubyid_number'>number</span> <span class='op'><=></span> <span class='id identifier rubyid_y'>y</span><span class='period'>.</span><span class='id identifier rubyid_number'>number</span> <span class='rbrace'>}</span>
<span class='id identifier rubyid_locks_in_order'>locks_in_order</span><span class='lbracket'>[</span><span class='int'>0</span><span class='rbracket'>]</span><span class='period'>.</span><span class='id identifier rubyid_synchronize'>synchronize</span> <span class='kw'>do</span>
<span class='id identifier rubyid_locks_in_order'>locks_in_order</span><span class='lbracket'>[</span><span class='int'>1</span><span class='rbracket'>]</span><span class='period'>.</span><span class='id identifier rubyid_synchronize'>synchronize</span> <span class='kw'>do</span>
<span class='id identifier rubyid_a'>a</span><span class='period'>.</span><span class='id identifier rubyid_value'>value</span> <span class='op'>-=</span> <span class='int'>10</span>
<span class='id identifier rubyid_b'>b</span><span class='period'>.</span><span class='id identifier rubyid_value'>value</span> <span class='op'>+=</span> <span class='int'>10</span>
<span class='kw'>end</span>
<span class='kw'>end</span>
</code></pre>
<p>That might work. But we need to know exactly what locks we're going to need
before we start. If there were conditions in side the transfer this might be
more complicated. We also need to remember the rescue code we had above to deal
with exceptions. This is getting out of hand - and it's where <code>TVar</code> comes in.</p>
<p>We'll model the accounts as <code>TVar</code> - transactional variable, and instead of
locks we'll use <code>Concurrent::atomically</code>.</p>
<pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_a'>a</span> <span class='op'>=</span> <span class='const'>TVar</span><span class='period'>.</span><span class='id identifier rubyid_new'><span class='object_link'><a href="Synchronization/Object.html#new-class_method" title="Concurrent::Synchronization::Object.new (method)">new</a></span></span><span class='lparen'>(</span><span class='int'>100_000</span><span class='rparen'>)</span>
<span class='id identifier rubyid_b'>b</span> <span class='op'>=</span> <span class='const'>TVar</span><span class='period'>.</span><span class='id identifier rubyid_new'><span class='object_link'><a href="Synchronization/Object.html#new-class_method" title="Concurrent::Synchronization::Object.new (method)">new</a></span></span><span class='lparen'>(</span><span class='int'>100</span><span class='rparen'>)</span>
<span class='const'><span class='object_link'><a href="../Concurrent.html" title="Concurrent (module)">Concurrent</a></span></span><span class='op'>::</span><span class='id identifier rubyid_atomically'><span class='object_link'><a href="../Concurrent.html#atomically-class_method" title="Concurrent.atomically (method)">atomically</a></span></span> <span class='kw'>do</span>
<span class='id identifier rubyid_a'>a</span><span class='period'>.</span><span class='id identifier rubyid_value'>value</span> <span class='op'>-=</span> <span class='int'>10</span>
<span class='id identifier rubyid_b'>b</span><span class='period'>.</span><span class='id identifier rubyid_value'>value</span> <span class='op'>+=</span> <span class='int'>10</span>
<span class='kw'>end</span>
</code></pre>
<p>That short piece of code effectively solves all the concerns we identified
above. How it does it is described in the reference above. You just need to be
happy that any two <code>atomically</code> blocks (we call them transactions) that use an
overlapping set of <code>TVar</code> objects will appear to have happened as if there was a
big global lock on them, and that if any exception is raised in the block, it
will be as if the block never happened. But also keep in mind the important
points we detailed right at the start of the article about side effects and
repeated execution.</p>
<h2>Evaluation</h2>
<p>We evaluated the performance of our <code>TVar</code> implementation using a bank account
simulation with a range of synchronisation implementations. The simulation
maintains a set of bank account totals, and runs transactions that either get a
summary statement of multiple accounts (a read-only operation) or transfers a
sum from one account to another (a read-write operation).</p>
<p>We implemented a bank that does not use any synchronisation (and so creates
inconsistent totals in accounts), one that uses a single global (or 'coarse')
lock (and so won't scale at all), one that uses one lock per account (and so has
a complicated system for locking in the correct order) and one using our <code>TVar</code>
and <code>atomically</code>.</p>
<p>We ran 1 million transactions divided equally between a varying number of
threads on a system that has at least that many physical cores. The transactions
are made up of a varying mixture of read-only and read-write transactions. We
ran each set of transactions thirty times, discarding the first ten and then
taking an algebraic mean. These graphs show only the simple mean. Our <code>tvars-
experiments</code> branch includes the benchmark used, full details of the test
system, and all the raw data.</p>
<p>Using JRuby using 75% read-write transactions, we can compare how the different
implementations of bank accounts scales to more cores. That is, how much faster
it runs if you use more cores.</p>
<p><img src="https://raw.githubusercontent.com/ruby-concurrency/concurrent-ruby/master/doc/images/tvar/implementation-scalability.png" alt=""></p>
<p>We see that the coarse lock implementation does not scale at all, and in fact
with more cores only wastes more time in contention for the single global lock.
We see that the unsynchronised implementation doesn't seem to scale well - which
is strange as there should be no overhead, but we'll explain that in a second.
We see that the fine lock implementation seems to scale better, and that the
<code>TVar</code> implementation scales the best.</p>
<p>So the <code>TVar</code> implementation <em>scales</em> very well, but how absolutely fast is it?</p>
<p><img src="https://raw.githubusercontent.com/ruby-concurrency/concurrent-ruby/master/doc/images/tvar/implementation-absolute.png" alt=""></p>
<p>Well, that's the downside. The unsynchronised implementation doesn't scale well
because it's so fast in the first place, and probably because we're bound on
access to the memory - the threads don't have much work to do, so no matter how
many threads we have the system is almost always reaching out to the L3 cache or
main memory. However remember that the unsynchronised implementation isn't
correct - the totals are wrong at the end. The coarse lock implementation has an
overhead of locking and unlocking. The fine lock implementation has a greater
overhead as as the locking scheme is complicated to avoid deadlock. It scales
better, however, actually allowing transactions to be processed in parallel. The
<code>TVar</code> implementation has a greater overhead still - and it's pretty huge. That
overhead is the cost for the simple programming model of an atomic block.</p>
<p>So that's what <code>TVar</code> gives you at the moment - great scalability, but it has a
high overhead. That's pretty much the state of software transactional memory in
general. Perhaps hardware transactional memory will help us, or perhaps we're
happy anyway with the simpler and safer programming model that the <code>TVar</code> gives
us.</p>
<p>We can also use this experiment to compare different implementations of Ruby. We
looked at just the <code>TVar</code> implementation and compared MRI 2.1.1, Rubinius 2.2.6,
and JRuby 1.7.11, again at 75% write transactions.</p>
<p><img src="https://raw.githubusercontent.com/ruby-concurrency/concurrent-ruby/master/doc/images/tvar/ruby-scalability.png" alt=""></p>
<p>We see that MRI provides no scalability, due to the global interpreter lock
(GIL). JRuby seems to scale better than Rubinius for this workload (there are of
course other workloads).</p>
<p>As before we should also look at the absolute performance, not just the
scalability.</p>
<p><img src="https://raw.githubusercontent.com/ruby-concurrency/concurrent-ruby/master/doc/images/tvar/ruby-absolute.png" alt=""></p>
<p>Again, JRuby seems to be faster than Rubinius for this experiment.
Interestingly, Rubinius looks slower than MRI for 1 core, but we can get around
that by using more cores.</p>
<p>We've used 75% read-write transactions throughout. We'll just take a quick look
at how the scalability varies for different workloads, for scaling between 1 and
2 threads. We'll admit that we used 75% read-write just because it emphasised
the differences.</p>
<p><img src="https://raw.githubusercontent.com/ruby-concurrency/concurrent-ruby/master/doc/images/tvar/implementation-write-proportion-scalability.png" alt=""></p>
<p>Finally, we can also run on a larger machine. We repeated the experiment using a
machine with 64 physical cores and JRuby.</p>
<p><img src="https://raw.githubusercontent.com/ruby-concurrency/concurrent-ruby/master/doc/images/tvar/implementation-scalability.png" alt=""></p>
<p><img src="https://raw.githubusercontent.com/ruby-concurrency/concurrent-ruby/master/doc/images/tvar/implementation-absolute.png" alt=""></p>
<p>Here you can see that <code>TVar</code> does become absolutely faster than using a global
lock, at the slightly ridiculously thread-count of 50. It's probably not
statistically significant anyway.</li>
</ul>
</div>
</div>
<div class="tags">
</div>
<h2>
Instance Method Summary
<small><a href="#" class="summary_toggle">collapse</a></small>
</h2>
<ul class="summary">
<li class="public ">
<span class="summary_signature">
<a href="#initialize-instance_method" title="#initialize (instance method)">#<strong>initialize</strong>(value) ⇒ TVar </a>
</span>
<span class="note title constructor">constructor</span>
<span class="summary_desc"><div class='inline'><p>Create a new <code>TVar</code> with an initial value.</p>
</div></span>
</li>
<li class="public ">
<span class="summary_signature">
<a href="#value-instance_method" title="#value (instance method)">#<strong>value</strong> ⇒ undocumented </a>
</span>
<span class="summary_desc"><div class='inline'><p>Get the value of a <code>TVar</code>.</p>
</div></span>
</li>
<li class="public ">
<span class="summary_signature">
<a href="#value=-instance_method" title="#value= (instance method)">#<strong>value=</strong>(value) ⇒ undocumented </a>
</span>
<span class="summary_desc"><div class='inline'><p>Set the value of a <code>TVar</code>.</p>
</div></span>
</li>
</ul>
<div id="constructor_details" class="method_details_list">
<h2>Constructor Details</h2>
<div class="method_details first">
<h3 class="signature first" id="initialize-instance_method">
#<strong>initialize</strong>(value) ⇒ <tt><span class='object_link'><a href="" title="Concurrent::TVar (class)">TVar</a></span></tt>
</h3><div class="docstring">
<div class="discussion">
<p>Create a new <code>TVar</code> with an initial value.</p>
</div>
</div>
<div class="tags">
</div><table class="source_code">
<tr>
<td>
<pre class="lines">
16
17
18
19
20</pre>
</td>
<td>
<pre class="code"><span class="info file"># File 'lib/concurrent/tvar.rb', line 16</span>
<span class='kw'>def</span> <span class='id identifier rubyid_initialize'>initialize</span><span class='lparen'>(</span><span class='id identifier rubyid_value'>value</span><span class='rparen'>)</span>
<span class='ivar'>@value</span> <span class='op'>=</span> <span class='id identifier rubyid_value'>value</span>
<span class='ivar'>@version</span> <span class='op'>=</span> <span class='int'>0</span>
<span class='ivar'>@lock</span> <span class='op'>=</span> <span class='const'>Mutex</span><span class='period'>.</span><span class='id identifier rubyid_new'>new</span>
<span class='kw'>end</span></pre>
</td>
</tr>
</table>
</div>
</div>
<div id="instance_method_details" class="method_details_list">
<h2>Instance Method Details</h2>
<div class="method_details first">
<h3 class="signature first" id="value-instance_method">
#<strong>value</strong> ⇒ <tt>undocumented</tt>
</h3><div class="docstring">
<div class="discussion">
<p>Get the value of a <code>TVar</code>.</p>
</div>
</div>
<div class="tags">
</div><table class="source_code">
<tr>
<td>
<pre class="lines">
23
24
25
26
27</pre>
</td>
<td>
<pre class="code"><span class="info file"># File 'lib/concurrent/tvar.rb', line 23</span>
<span class='kw'>def</span> <span class='id identifier rubyid_value'>value</span>
<span class='const'><span class='object_link'><a href="../Concurrent.html" title="Concurrent (module)">Concurrent</a></span></span><span class='op'>::</span><span class='id identifier rubyid_atomically'><span class='object_link'><a href="../Concurrent.html#atomically-class_method" title="Concurrent.atomically (method)">atomically</a></span></span> <span class='kw'>do</span>
<span class='const'><span class='object_link'><a href="Transaction.html" title="Concurrent::Transaction (class)">Transaction</a></span></span><span class='op'>::</span><span class='id identifier rubyid_current'><span class='object_link'><a href="Transaction.html#current-class_method" title="Concurrent::Transaction.current (method)">current</a></span></span><span class='period'>.</span><span class='id identifier rubyid_read'>read</span><span class='lparen'>(</span><span class='kw'>self</span><span class='rparen'>)</span>
<span class='kw'>end</span>
<span class='kw'>end</span></pre>
</td>
</tr>
</table>
</div>
<div class="method_details ">
<h3 class="signature " id="value=-instance_method">
#<strong>value=</strong>(value) ⇒ <tt>undocumented</tt>
</h3><div class="docstring">
<div class="discussion">
<p>Set the value of a <code>TVar</code>.</p>
</div>
</div>
<div class="tags">
</div><table class="source_code">
<tr>
<td>
<pre class="lines">
30
31
32
33
34</pre>
</td>
<td>
<pre class="code"><span class="info file"># File 'lib/concurrent/tvar.rb', line 30</span>
<span class='kw'>def</span> <span class='id identifier rubyid_value='>value=</span><span class='lparen'>(</span><span class='id identifier rubyid_value'>value</span><span class='rparen'>)</span>
<span class='const'><span class='object_link'><a href="../Concurrent.html" title="Concurrent (module)">Concurrent</a></span></span><span class='op'>::</span><span class='id identifier rubyid_atomically'><span class='object_link'><a href="../Concurrent.html#atomically-class_method" title="Concurrent.atomically (method)">atomically</a></span></span> <span class='kw'>do</span>
<span class='const'><span class='object_link'><a href="Transaction.html" title="Concurrent::Transaction (class)">Transaction</a></span></span><span class='op'>::</span><span class='id identifier rubyid_current'><span class='object_link'><a href="Transaction.html#current-class_method" title="Concurrent::Transaction.current (method)">current</a></span></span><span class='period'>.</span><span class='id identifier rubyid_write'>write</span><span class='lparen'>(</span><span class='kw'>self</span><span class='comma'>,</span> <span class='id identifier rubyid_value'>value</span><span class='rparen'>)</span>
<span class='kw'>end</span>
<span class='kw'>end</span></pre>
</td>
</tr>
</table>
</div>
</div>
</div>
<div id="footer">
Generated by <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_blank">yard</a>.
</div>
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-57940973-1', 'auto');
ga('send', 'pageview');
</script>
</div>
</body>
</html>