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 } }
Creates a new Mutex
static VALUE
mutex_initialize(VALUE self)
{
return self;
}
Attempts to grab the lock and waits if it isn’t available. Raises
ThreadError if mutex was locked by the current
thread.
VALUE
rb_mutex_lock(VALUE self)
{
if (rb_mutex_trylock(self) == Qfalse) {
mutex_t *mutex;
rb_thread_t *th = GET_THREAD();
GetMutexPtr(self, mutex);
if (mutex->th == GET_THREAD()) {
rb_raise(rb_eThreadError, "deadlock; recursive locking");
}
while (mutex->th != th) {
int interrupted;
enum rb_thread_status prev_status = th->status;
int last_thread = 0;
struct rb_unblock_callback oldubf;
set_unblock_function(th, lock_interrupt, mutex, &oldubf);
th->status = THREAD_STOPPED_FOREVER;
th->vm->sleeper++;
th->locking_mutex = self;
if (vm_living_thread_num(th->vm) == th->vm->sleeper) {
last_thread = 1;
}
th->transition_for_lock = 1;
BLOCKING_REGION_CORE({
interrupted = lock_func(th, mutex, last_thread);
});
th->transition_for_lock = 0;
remove_signal_thread_list(th);
reset_unblock_function(th, &oldubf);
th->locking_mutex = Qfalse;
if (mutex->th && interrupted == 2) {
rb_check_deadlock(th->vm);
}
if (th->status == THREAD_STOPPED_FOREVER) {
th->status = prev_status;
}
th->vm->sleeper--;
if (mutex->th == th) mutex_locked(th, self);
if (interrupted) {
RUBY_VM_CHECK_INTS();
}
}
}
return self;
}
Returns true if this lock is currently held by some thread.
VALUE
rb_mutex_locked_p(VALUE self)
{
mutex_t *mutex;
GetMutexPtr(self, mutex);
return mutex->th ? Qtrue : Qfalse;
}
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.
static VALUE
mutex_sleep(int argc, VALUE *argv, VALUE self)
{
VALUE timeout;
rb_scan_args(argc, argv, "01", &timeout);
return rb_mutex_sleep(self, timeout);
}
Attempts to obtain the lock and returns immediately. Returns
true if the lock was granted.
VALUE
rb_mutex_trylock(VALUE self)
{
mutex_t *mutex;
VALUE locked = Qfalse;
GetMutexPtr(self, mutex);
native_mutex_lock(&mutex->lock);
if (mutex->th == 0) {
mutex->th = GET_THREAD();
locked = Qtrue;
mutex_locked(GET_THREAD(), self);
}
native_mutex_unlock(&mutex->lock);
return locked;
}
Releases the lock. Raises ThreadError if mutex
wasn’t locked by the current thread.
VALUE
rb_mutex_unlock(VALUE self)
{
const char *err;
mutex_t *mutex;
GetMutexPtr(self, mutex);
err = mutex_unlock(mutex, GET_THREAD());
if (err) rb_raise(rb_eThreadError, "%s", err);
return self;
}
Commenting is here to help enhance the documentation. For example, code samples, or clarification of the documentation.
If you have questions about Ruby or the documentation, please post to one of the Ruby mailing lists. You will get better, faster, help that way.
If you wish to post a correction of the docs, please do so, but also file bug report so that it can be corrected for the next release. Thank you.
If you want to help improve the Ruby documentation, please see Improve the docs, or visit Documenting-ruby.org.