110 lines
2.8 KiB
Ruby
110 lines
2.8 KiB
Ruby
|
require 'thread'
|
||
|
require 'concurrent/synchronization'
|
||
|
|
||
|
module Concurrent
|
||
|
|
||
|
# Old school kernel-style event reminiscent of Win32 programming in C++.
|
||
|
#
|
||
|
# When an `Event` is created it is in the `unset` state. Threads can choose to
|
||
|
# `#wait` on the event, blocking until released by another thread. When one
|
||
|
# thread wants to alert all blocking threads it calls the `#set` method which
|
||
|
# will then wake up all listeners. Once an `Event` has been set it remains set.
|
||
|
# New threads calling `#wait` will return immediately. An `Event` may be
|
||
|
# `#reset` at any time once it has been set.
|
||
|
#
|
||
|
# @see http://msdn.microsoft.com/en-us/library/windows/desktop/ms682655.aspx
|
||
|
# @example
|
||
|
# event = Concurrent::Event.new
|
||
|
#
|
||
|
# t1 = Thread.new do
|
||
|
# puts "t1 is waiting"
|
||
|
# event.wait(1)
|
||
|
# puts "event ocurred"
|
||
|
# end
|
||
|
#
|
||
|
# t2 = Thread.new do
|
||
|
# puts "t2 calling set"
|
||
|
# event.set
|
||
|
# end
|
||
|
#
|
||
|
# [t1, t2].each(&:join)
|
||
|
#
|
||
|
# # prints:
|
||
|
# # t2 calling set
|
||
|
# # t1 is waiting
|
||
|
# # event occurred
|
||
|
class Event < Synchronization::LockableObject
|
||
|
|
||
|
# Creates a new `Event` in the unset state. Threads calling `#wait` on the
|
||
|
# `Event` will block.
|
||
|
def initialize
|
||
|
super
|
||
|
synchronize { ns_initialize }
|
||
|
end
|
||
|
|
||
|
# Is the object in the set state?
|
||
|
#
|
||
|
# @return [Boolean] indicating whether or not the `Event` has been set
|
||
|
def set?
|
||
|
synchronize { @set }
|
||
|
end
|
||
|
|
||
|
# Trigger the event, setting the state to `set` and releasing all threads
|
||
|
# waiting on the event. Has no effect if the `Event` has already been set.
|
||
|
#
|
||
|
# @return [Boolean] should always return `true`
|
||
|
def set
|
||
|
synchronize { ns_set }
|
||
|
end
|
||
|
|
||
|
def try?
|
||
|
synchronize { @set ? false : ns_set }
|
||
|
end
|
||
|
|
||
|
# Reset a previously set event back to the `unset` state.
|
||
|
# Has no effect if the `Event` has not yet been set.
|
||
|
#
|
||
|
# @return [Boolean] should always return `true`
|
||
|
def reset
|
||
|
synchronize do
|
||
|
if @set
|
||
|
@set = false
|
||
|
@iteration +=1
|
||
|
end
|
||
|
true
|
||
|
end
|
||
|
end
|
||
|
|
||
|
# Wait a given number of seconds for the `Event` to be set by another
|
||
|
# thread. Will wait forever when no `timeout` value is given. Returns
|
||
|
# immediately if the `Event` has already been set.
|
||
|
#
|
||
|
# @return [Boolean] true if the `Event` was set before timeout else false
|
||
|
def wait(timeout = nil)
|
||
|
synchronize do
|
||
|
unless @set
|
||
|
iteration = @iteration
|
||
|
ns_wait_until(timeout) { iteration < @iteration || @set }
|
||
|
else
|
||
|
true
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
protected
|
||
|
|
||
|
def ns_set
|
||
|
unless @set
|
||
|
@set = true
|
||
|
ns_broadcast
|
||
|
end
|
||
|
true
|
||
|
end
|
||
|
|
||
|
def ns_initialize
|
||
|
@set = false
|
||
|
@iteration = 0
|
||
|
end
|
||
|
end
|
||
|
end
|