# class Thread::Mutex

`Mutex`

### Public Class Methods

new → mutex click to toggle source

Creates a new `Mutex`

    static VALUE
    mutex_initialize(VALUE self)
    {
        return self;
    }

### Public Instance Methods

lock → self click to toggle source

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)
    {
        rb_thread_t *th = GET_THREAD();
        rb_mutex_t *mutex;
        GetMutexPtr(self, mutex);

        /* When running trap handler */
        if (!mutex->allow_trap && th->interrupt_mask & TRAP_INTERRUPT_MASK) {
            rb_raise(rb_eThreadError, "can't be called from trap context");
        }

        if (rb_mutex_trylock(self) == Qfalse) {
            if (mutex->th == th) {
                rb_raise(rb_eThreadError, "deadlock; recursive locking");
            }

            while (mutex->th != th) {
                int interrupted;
                enum rb_thread_status prev_status = th->status;
                volatile int timeout_ms = 0;
                struct rb_unblock_callback oldubf;

                set_unblock_function(th, lock_interrupt, mutex, &oldubf, FALSE);
                th->status = THREAD_STOPPED_FOREVER;
                th->locking_mutex = self;

                native_mutex_lock(&mutex->lock);
                th->vm->sleeper++;
                /*
                 * Carefully! while some contended threads are in lock_func(),
                 * vm->sleepr is unstable value. we have to avoid both deadlock
                 * and busy loop.
                 */
                if ((vm_living_thread_num(th->vm) == th->vm->sleeper) &&
                    !patrol_thread) {
                    timeout_ms = 100;
                    patrol_thread = th;
                }

                GVL_UNLOCK_BEGIN();
                interrupted = lock_func(th, mutex, (int)timeout_ms);
                native_mutex_unlock(&mutex->lock);
                GVL_UNLOCK_END();

                if (patrol_thread == th)
                    patrol_thread = NULL;

                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_BLOCKING(th); /* may release mutex */
                    if (!mutex->th) {
                        mutex->th = th;
                        mutex_locked(th, self);
                    }
                }
            }
        }
        return self;
    }

locked? → true or false click to toggle source

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

    VALUE
    rb_mutex_locked_p(VALUE self)
    {
        rb_mutex_t *mutex;
        GetMutexPtr(self, mutex);
        return mutex->th ? Qtrue : Qfalse;
    }

owned? → true or false click to toggle source

Returns `true` if this lock is currently held by current thread.

    VALUE
    rb_mutex_owned_p(VALUE self)
    {
        VALUE owned = Qfalse;
        rb_thread_t *th = GET_THREAD();
        rb_mutex_t *mutex;

        GetMutexPtr(self, mutex);

        if (mutex->th == th)
            owned = Qtrue;

        return owned;
    }

sleep(timeout = nil) → number click to toggle source

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.

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

synchronize { ... } → result of the block click to toggle source

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

    static VALUE
    rb_mutex_synchronize_m(VALUE self, VALUE args)
    {
        if (!rb_block_given_p()) {
            rb_raise(rb_eThreadError, "must be called with a block");
        }

        return rb_mutex_synchronize(self, rb_yield, Qundef);
    }

try_lock → true or false click to toggle source

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

    VALUE
    rb_mutex_trylock(VALUE self)
    {
        rb_mutex_t *mutex;
        VALUE locked = Qfalse;
        GetMutexPtr(self, mutex);

        native_mutex_lock(&mutex->lock);
        if (mutex->th == 0) {
            rb_thread_t *th = GET_THREAD();
            mutex->th = th;
            locked = Qtrue;

            mutex_locked(th, self);
        }
        native_mutex_unlock(&mutex->lock);

        return locked;
    }

unlock → self click to toggle source

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

    VALUE
    rb_mutex_unlock(VALUE self)
    {
        const char *err;
        rb_mutex_t *mutex;
        GetMutexPtr(self, mutex);

        err = rb_mutex_unlock_th(mutex, GET_THREAD());
        if (err) rb_raise(rb_eThreadError, "%s", err);

        return self;
    }