Class: Thread::Mutex
Instance Method Summary collapse
-
#new ⇒ Object
constructor
Creates a new Mutex.
-
#lock ⇒ self
Attempts to grab the lock and waits if it isn’t available.
-
#locked? ⇒ Boolean
Returns
true
if this lock is currently held by some thread. -
#owned? ⇒ Boolean
Returns
true
if this lock is currently held by current thread. -
#sleep(timeout = nil) ⇒ Numeric
Releases the lock and sleeps
timeout
seconds if it is given and non-nil or forever. -
#synchronize { ... } ⇒ Object
Obtains a lock, runs the block, and releases the lock when the block completes.
-
#try_lock ⇒ Boolean
Attempts to obtain the lock and returns immediately.
-
#unlock ⇒ self
Releases the lock.
Constructor Details
#new ⇒ Object
Creates a new Mutex
109 110 111 112 113 |
# File 'thread_sync.c', line 109
static VALUE
mutex_initialize(VALUE self)
{
return self;
}
|
Instance Method Details
#lock ⇒ self
Attempts to grab the lock and waits if it isn’t available. Raises ThreadError
if mutex
was locked by the current thread.
238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 |
# File 'thread_sync.c', line 238
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);
}
}
}
return self;
}
|
#locked? ⇒ Boolean
Returns true
if this lock is currently held by some thread.
127 128 129 130 131 132 133 |
# File 'thread_sync.c', line 127
VALUE
rb_mutex_locked_p(VALUE self)
{
rb_mutex_t *mutex;
GetMutexPtr(self, mutex);
return mutex->th ? Qtrue : Qfalse;
}
|
#owned? ⇒ Boolean
Returns true
if this lock is currently held by current thread.
313 314 315 316 317 318 319 320 321 322 323 324 325 326 |
# File 'thread_sync.c', line 313
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) ⇒ Numeric
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.
466 467 468 469 470 471 472 473 |
# File 'thread_sync.c', line 466
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 { ... } ⇒ Object
Obtains a lock, runs the block, and releases the lock when the block completes. See the example under Mutex
.
497 498 499 500 501 502 503 504 505 |
# File 'thread_sync.c', line 497
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 ⇒ Boolean
Attempts to obtain the lock and returns immediately. Returns true
if the lock was granted.
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 |
# File 'thread_sync.c', line 154
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
Releases the lock. Raises ThreadError
if mutex
wasn’t locked by the current thread.
368 369 370 371 372 373 374 375 376 377 378 379 |
# File 'thread_sync.c', line 368
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;
}
|