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)


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

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(WeakRef.new(@thread))
end

Class Method Details

.finalizer(thread) ⇒ Object



42
43
44
45
46
47
48
49
50
51
52
# File 'lib/thread/future.rb', line 42

def self.finalizer(thread)
	proc {
		if thread.weakref_alive?
			if thread.is_a? Thread
				thread.raise Cancel
			else
				thread.terminate! Cancel
			end
		end
	}
end

Instance Method Details

#cancelObject

Cancel the future, #value will yield a Cancel exception



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/thread/future.rb', line 78

def cancel
	return self if delivered?

	@mutex.synchronize {
		if @thread.is_a? Thread
			@thread.raise Cancel
		else
			@thread.terminate! Cancel
		end

		@exception = Cancel.new
	}

	self
end

#cancelled?Boolean

Check if the future has been cancelled

Returns:

  • (Boolean)


95
96
97
98
99
# File 'lib/thread/future.rb', line 95

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

#delivered?Boolean Also known as: realized?

Check if the future has been called.

Returns:

  • (Boolean)


69
70
71
72
73
# File 'lib/thread/future.rb', line 69

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

#exceptionObject

Return the raised exception.



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

def exception
	@mutex.synchronize {
		@exception
	}
end

#exception?Boolean

Check if an exception has been raised.

Returns:

  • (Boolean)


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

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:



108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/thread/future.rb', line 108

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.



127
128
129
130
131
132
133
# File 'lib/thread/future.rb', line 127

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