Class: Mutex

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

Overview

Mutex implements a simple semaphore that can be used to coordinate access to shared data from multiple concurrent threads.

Example:

require 'thread'
semaphore = Mutex.new

a = Thread.new {
  semaphore.synchronize {
    # access shared resource
  }
}

b = Thread.new {
  semaphore.synchronize {
    # access shared resource
  }
}

Instance Method Summary collapse

Constructor Details

#initializeMutex

Creates a new Mutex



60
61
62
63
64
65
# File 'lib/thread.rb', line 60

def initialize
  @waiting = []
  @locked = false;
  @waiting.taint		# enable tainted comunication
  self.taint
end

Instance Method Details

#exclusive_unlock { ... } ⇒ Object

If the mutex is locked, unlocks the mutex, wakes one waiting thread, and yields in a critical section.

Yields:



140
141
142
143
144
145
146
147
148
149
150
151
152
153
# File 'lib/thread.rb', line 140

def exclusive_unlock
  return unless @locked
  Thread.exclusive do
    @locked = false
    begin
	t = @waiting.shift
	t.wakeup if t
    rescue ThreadError
	retry
    end
    yield
  end
  self
end

#lockObject

Attempts to grab the lock and waits if it isn't available.



92
93
94
95
96
97
98
99
100
# File 'lib/thread.rb', line 92

def lock
  while (Thread.critical = true; @locked)
    @waiting.push Thread.current
    Thread.stop
  end
  @locked = true
  Thread.critical = false
  self
end

#locked?Object

Returns true if this lock is currently held by some thread.



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/thread.rb', line 70

/*
 * Document-method: locked?
 * call-seq: locked?
 *
 * Returns +true+ if this lock is currently held by some thread.
 *
 */

static VALUE
rb_mutex_locked_p(VALUE self)
{
    Mutex *mutex;
    Data_Get_Struct(self, Mutex, mutex);
    return MUTEX_LOCKED_P(mutex) ? Qtrue : Qfalse;
}

#marshal_dumpObject

#marshal_loadObject

for marshalling mutexes and condvars



# File 'thread.c'

/* for marshalling mutexes and condvars */

static VALUE
dummy_load(VALUE self, VALUE string)
{
    return Qnil;
}

#synchronize { ... } ⇒ Object

Obtains a lock, runs the block, and releases the lock when the block completes. See the example under Mutex.

Yields:



127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/thread.rb', line 127

/*
 * Document-method: synchronize
 * call-seq: synchronize { ... }
 *
 * Obtains a lock, runs the block, and releases the lock when the block
 * completes.  See the example under Mutex.
 *
 */

static VALUE
rb_mutex_synchronize(VALUE self)
{
    rb_mutex_lock(self);
    return rb_ensure(rb_yield, Qundef, rb_mutex_unlock, self);
}

#try_lockObject

Attempts to obtain the lock and returns immediately. Returns true if the lock was granted.



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/thread.rb', line 78

/*
 * Document-method: try_lock
 * call-seq: try_lock
 *
 * Attempts to obtain the lock and returns immediately. Returns +true+ if the
 * lock was granted.
 *
 */

static VALUE
rb_mutex_try_lock(VALUE self)
{
    Mutex *mutex;

    Data_Get_Struct(self, Mutex, mutex);

    if (MUTEX_LOCKED_P(mutex))
        return Qfalse;

    mutex->owner = rb_thread_current();
    return Qtrue;
}

#unlockObject

Releases the lock. Returns nil if ref wasn't locked.



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

def unlock
  return unless @locked
  Thread.critical = true
  @locked = false
  begin
    t = @waiting.shift
    t.wakeup if t
  rescue ThreadError
    retry
  end
  Thread.critical = false
  begin
    t.run if t
  rescue ThreadError
  end
  self
end