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; }