Class: Mutex

Inherits:
Object show all
Defined in:
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

- (Object) new

Creates a new Mutex



# File 'thread.c'

/*
 *  call-seq:
 *     Mutex.new   -> mutex
 *
 *  Creates a new Mutex
 */
static VALUE
mutex_initialize(VALUE self)
{
    return self;
}

Instance Method Details

- (Mutex) lock

Attempts to grab the lock and waits if it isn't available. Raises ThreadError if mutex was locked by the current thread.



# File 'thread.c'

/*
 * 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.
 */
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;
}

- (Boolean) locked?

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



# File 'thread.c'

/*
 * call-seq:
 *    mutex.locked?  -> true or false
 *
 * 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;
}

- (Numeric) sleep(timeout = 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.



# File 'thread.c'

/*
 * call-seq:
 *    mutex.sleep(timeout = nil)    -> number
 *
 * 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);
}

- (Boolean) try_lock

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



# File 'thread.c'

/*
 * call-seq:
 *    mutex.try_lock  -> true or false
 *
 * 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;
}

- (Mutex) unlock

Releases the lock. Raises ThreadError if mutex wasn't locked by the current thread.



# File 'thread.c'

/*
 * call-seq:
 *    mutex.unlock    -> self
 *
 * 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;
}