summaryrefslogtreecommitdiff
path: root/thread_sync.rb
blob: 28c70b1e9ce8fbeaeaee50d22e6b06f10ff3aebe (plain)
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
# frozen_string_literal: true

class Thread
  class Queue
    # call-seq:
    #   pop(non_block=false, timeout: nil)
    #
    # Retrieves data from the queue.
    #
    # If the queue is empty, the calling thread is suspended until data is pushed
    # onto the queue. If +non_block+ is true, the thread isn't suspended, and
    # +ThreadError+ is raised.
    #
    # If +timeout+ seconds have passed and no data is available +nil+ is
    # returned. If +timeout+ is +0+ it returns immediately.
    def pop(non_block = false, timeout: nil)
      if non_block && timeout
        raise ArgumentError, "can't set a timeout if non_block is enabled"
      end
      Primitive.rb_queue_pop(non_block, timeout)
    end
    alias_method :deq, :pop
    alias_method :shift, :pop
  end

  class SizedQueue
    # call-seq:
    #   pop(non_block=false, timeout: nil)
    #
    # Retrieves data from the queue.
    #
    # If the queue is empty, the calling thread is suspended until data is
    # pushed onto the queue. If +non_block+ is true, the thread isn't
    # suspended, and +ThreadError+ is raised.
    #
    # If +timeout+ seconds have passed and no data is available +nil+ is
    # returned. If +timeout+ is +0+ it returns immediately.
    def pop(non_block = false, timeout: nil)
      if non_block && timeout
        raise ArgumentError, "can't set a timeout if non_block is enabled"
      end
      Primitive.rb_szqueue_pop(non_block, timeout)
    end
    alias_method :deq, :pop
    alias_method :shift, :pop

    # call-seq:
    #   push(object, non_block=false, timeout: nil)
    #   enq(object, non_block=false, timeout: nil)
    #   <<(object)
    #
    # Pushes +object+ to the queue.
    #
    # If there is no space left in the queue, waits until space becomes
    # available, unless +non_block+ is true.  If +non_block+ is true, the
    # thread isn't suspended, and +ThreadError+ is raised.
    #
    # If +timeout+ seconds have passed and no space is available +nil+ is
    # returned. If +timeout+ is +0+ it returns immediately.
    # Otherwise it returns +self+.
    def push(object, non_block = false, timeout: nil)
      if non_block && timeout
        raise ArgumentError, "can't set a timeout if non_block is enabled"
      end
      Primitive.rb_szqueue_push(object, non_block, timeout)
    end
    alias_method :enq, :push
    alias_method :<<, :push
  end

  class Mutex
    # call-seq:
    #    Thread::Mutex.new   -> mutex
    #
    # Creates a new Mutex
    def initialize
    end

    # call-seq:
    #    mutex.locked?  -> true or false
    #
    # Returns +true+ if this lock is currently held by some thread.
    def locked?
      Primitive.cexpr! %q{ RBOOL(mutex_locked_p(mutex_ptr(self))) }
    end

    # call-seq:
    #    mutex.owned?  -> true or false
    #
    # Returns +true+ if this lock is currently held by current thread.
    def owned?
      Primitive.rb_mut_owned_p
    end

    # call-seq:
    #    mutex.lock  -> self
    #
    # Attempts to grab the lock and waits if it isn't available.
    # Raises +ThreadError+ if +mutex+ was locked by the current thread.
    def lock
      Primitive.rb_mut_lock
    end

    # call-seq:
    #    mutex.try_lock  -> true or false
    #
    # Attempts to obtain the lock and returns immediately. Returns +true+ if the
    # lock was granted.
    def try_lock
      Primitive.rb_mut_trylock
    end

    # call-seq:
    #    mutex.lock  -> self
    #
    # Attempts to grab the lock and waits if it isn't available.
    # Raises +ThreadError+ if +mutex+ was locked by the current thread.
    def unlock
      Primitive.rb_mut_unlock
    end

    # call-seq:
    #    mutex.synchronize { ... }    -> result of the block
    #
    # Obtains a lock, runs the block, and releases the lock when the block
    # completes.  See the example under Thread::Mutex.
    def synchronize
      raise ThreadError, "must be called with a block" unless defined?(yield)

      Primitive.rb_mut_synchronize
    end

    # call-seq:
    #    mutex.sleep(timeout = nil)    -> number or nil
    #
    # Releases the lock and sleeps +timeout+ seconds if it is given and
    # non-nil or forever.  Raises +ThreadError+ if +mutex+ wasn't locked by
    # the current thread.
    #
    # When the thread is next woken up, it will attempt to reacquire
    # the lock.
    #
    # Note that this method can wakeup without explicit Thread#wakeup call.
    # For example, receiving signal and so on.
    #
    # Returns the slept time in seconds if woken up, or +nil+ if timed out.
    def sleep(timeout = nil)
      Primitive.rb_mut_sleep(timeout)
    end
  end
end