# Class: Concurrent::Exchanger

Inherits:
  ExchangerImplementation
  - Object
  - Concurrent::Exchanger
  show all

Defined in:
  lib/concurrent/exchanger.rb

## Overview

A synchronization point at which threads can pair and swap elements within pairs. Each thread presents some object on entry to the exchange method, matches with a partner thread, and receives its partner's object on return.

## Thread-safe Variable Classes

Each of the thread-safe variable classes is designed to solve a different problem. In general:

- Agent: Shared, mutable variable providing independent, uncoordinated, asynchronous 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.
- Atom: Shared, mutable variable providing independent, uncoordinated, synchronous 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.
- AtomicReference: 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. AtomicBoolean and AtomicFixnum are similar but optimized for the given data type.
- Exchanger: 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.
- MVar: 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.
- ThreadLocalVar: 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.
- TVar: Shared, mutable variables which provide coordinated, synchronous, change of many stated. Used when multiple value must change together, in an all-or-nothing transaction. This implementation is very simple, using only a single slot for each exchanger (unlike more advanced implementations which use an "arena"). This approach will work perfectly fine when there are only a few threads accessing a single `Exchanger`. Beyond a handful of threads the performance will degrade rapidly due to contention on the single slot, but the algorithm will remain correct.

Examples:

    exchanger = Concurrent::Exchanger.new

    threads = [
      Thread.new { puts "first: " << exchanger.exchange('foo', 1) }, #=> "first: bar"
      Thread.new { puts "second: " << exchanger.exchange('bar', 1) } #=> "second: foo"
    ]
    threads.each {|t| t.join(2) }

See Also:

- java.util.concurrent.Exchanger

## Instance Method Summary collapse

- #exchange(value, timeout = nil) ⇒ Object

  Waits for another thread to arrive at this exchange point (unless the current thread is interrupted), and then transfers the given object to it, receiving its object in return.

- #exchange!(value, timeout = nil) ⇒ Object

  Waits for another thread to arrive at this exchange point (unless the current thread is interrupted), and then transfers the given object to it, receiving its object in return.

- #initialize ⇒ undocumented constructor

  Creates exchanger instance.

- #try_exchange(value, timeout = nil) ⇒ Concurrent::Maybe

  Waits for another thread to arrive at this exchange point (unless the current thread is interrupted), and then transfers the given object to it, receiving its object in return.

## Constructor Details

### #initialize ⇒ `undocumented`

Creates exchanger instance

    # File 'lib/concurrent/exchanger.rb', line 337

## Instance Method Details

### #exchange(value, timeout = nil) ⇒ `Object`

Waits for another thread to arrive at this exchange point (unless the current thread is interrupted), and then transfers the given object to it, receiving its object in return. The timeout value indicates the approximate number of seconds the method should block while waiting for the exchange. When the timeout value is `nil` the method will block indefinitely.

In some edge cases when a `timeout` is given a return value of `nil` may be ambiguous. Specifically, if `nil` is a valid value in the exchange it will be impossible to tell whether `nil` is the actual return value or if it signifies timeout. When `nil` is a valid value in the exchange consider using #exchange! or #try_exchange instead.

Parameters:

- value (`Object`) —

  the value to exchange with another thread

- timeout (`Numeric`, `nil`) (defaults to: `nil`) —

  in seconds, `nil` blocks indefinitely

Returns:

- (`Object`) —

  the value exchanged by the other thread or `nil` on timeout

    # File 'lib/concurrent/exchanger.rb', line 340

### #exchange!(value, timeout = nil) ⇒ `Object`

Waits for another thread to arrive at this exchange point (unless the current thread is interrupted), and then transfers the given object to it, receiving its object in return. The timeout value indicates the approximate number of seconds the method should block while waiting for the exchange. When the timeout value is `nil` the method will block indefinitely.

On timeout a TimeoutError exception will be raised.

Parameters:

- value (`Object`) —

  the value to exchange with another thread

- timeout (`Numeric`, `nil`) (defaults to: `nil`) —

  in seconds, `nil` blocks indefinitely

Returns:

- (`Object`) —

  the value exchanged by the other thread

Raises:

- (`Concurrent::TimeoutError`) —

  on timeout

    # File 'lib/concurrent/exchanger.rb', line 344

### #try_exchange(value, timeout = nil) ⇒ `Concurrent::Maybe`

Waits for another thread to arrive at this exchange point (unless the current thread is interrupted), and then transfers the given object to it, receiving its object in return. The timeout value indicates the approximate number of seconds the method should block while waiting for the exchange. When the timeout value is `nil` the method will block indefinitely.

The return value will be a Maybe set to `Just` on success or `Nothing` on timeout.

Examples:

    exchanger = Concurrent::Exchanger.new

    result = exchanger.exchange(:foo, 0.5)

    if result.just?
      puts result.value #=> :bar
    else
      puts 'timeout'
    end

Parameters:

- value (`Object`) —

  the value to exchange with another thread

- timeout (`Numeric`, `nil`) (defaults to: `nil`) —

  in seconds, `nil` blocks indefinitely

Returns:

- (`Concurrent::Maybe`) —

  on success a `Just` maybe will be returned with the item exchanged by the other thread as `#value`; on timeout a `Nothing` maybe will be returned with TimeoutError as `#reason`

    # File 'lib/concurrent/exchanger.rb', line 351