Class: Thread::Future

Inherits:
Object
  • Object
show all
Defined in:
lib/thread/future.rb

Overview

A future is an object that incapsulates a block which is called in a different thread, upon retrieval the caller gets blocked until the block has finished running, and its result is returned and cached.

Constant Summary collapse

Cancel =
Class.new(Exception)

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(pool = nil, &block) ⇒ Future

Create a future with the passed block and optionally using the passed pool.

Raises:

  • (ArgumentError)


20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# File 'lib/thread/future.rb', line 20

def initialize (pool = nil, &block)
	raise ArgumentError, 'no block given' unless block

	@mutex = Mutex.new

	task = proc {
		begin
			deliver block.call
		rescue Exception => e
			@exception = e

			deliver nil
		end
	}

	@thread = pool ? pool.process(&task) : Thread.new(&task)

	ObjectSpace.define_finalizer self, self.class.finalizer(@thread)
end

Class Method Details

.finalizer(thread) ⇒ Object



41
42
43
44
45
# File 'lib/thread/future.rb', line 41

def self.finalizer (thread)
	proc {
		thread.raise Cancel.new
	}
end

Instance Method Details

#cancelObject

Cancel the future, #value will yield a Cancel exception



71
72
73
74
75
76
77
78
79
# File 'lib/thread/future.rb', line 71

def cancel
	return self if delivered?

	@mutex.synchronize {
		@thread.raise Cancel.new('future cancelled')
	}

	self
end

#cancelled?Boolean

Check if the future has been cancelled

Returns:

  • (Boolean)


82
83
84
85
86
# File 'lib/thread/future.rb', line 82

def cancelled?
	@mutex.synchronize {
		@exception.is_a? Cancel
	}
end

#delivered?Boolean Also known as: realized?

Check if the future has been called.

Returns:

  • (Boolean)


62
63
64
65
66
# File 'lib/thread/future.rb', line 62

def delivered?
	@mutex.synchronize {
		instance_variable_defined? :@value
	}
end

#exceptionObject

Return the raised exception.



55
56
57
58
59
# File 'lib/thread/future.rb', line 55

def exception
	@mutex.synchronize {
		@exception
	}
end

#exception?Boolean

Check if an exception has been raised.

Returns:

  • (Boolean)


48
49
50
51
52
# File 'lib/thread/future.rb', line 48

def exception?
	@mutex.synchronize {
		instance_variable_defined? :@exception
	}
end

#value(timeout = nil) ⇒ Object Also known as: ~

Get the value of the future, if it’s not finished running this call will block.

In case the block raises an exception, it will be raised, the exception is cached and will be raised every time you access the value.

An optional timeout can be passed which will return nil if nothing has been delivered.

Raises:



95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/thread/future.rb', line 95

def value (timeout = nil)
	raise @exception if exception?

	return @value if delivered?

	@mutex.synchronize {
		cond.wait(@mutex, *timeout)
	}

	if exception?
		raise @exception
	elsif delivered?
		return @value
	end
end

#value!(timeout = nil) ⇒ Object Also known as: !

Do the same as #value, but return nil in case of exception.



114
115
116
117
118
119
120
# File 'lib/thread/future.rb', line 114

def value! (timeout = nil)
	begin
		value(timeout)
	rescue Exception
		nil
	end
end