Class: Fiber

Inherits:
Object show all
Defined in:
cont.c,
cont.c

Overview

Fibers are primitives for implementing light weight cooperative concurrency in Ruby. Basically they are a means of creating code blocks that can be paused and resumed, much like threads. The main difference is that they are never preempted and that the scheduling must be done by the programmer and not the VM.

As opposed to other stackless light weight concurrency models, each fiber comes with a stack. This enables the fiber to be paused from deeply nested function calls within the fiber block. See the ruby(1) manpage to configure the size of the fiber stack(s).

When a fiber is created it will not run automatically. Rather it must be explicitly asked to run using the Fiber#resume method. The code running inside the fiber can give up control by calling Fiber.yield in which case it yields control back to caller (the caller of the Fiber#resume).

Upon yielding or termination the Fiber returns the value of the last executed expression

For instance:

fiber = Fiber.new do
  Fiber.yield 1
  2
end

puts fiber.resume
puts fiber.resume
puts fiber.resume

produces

1
2
FiberError: dead fiber called

The Fiber#resume method accepts an arbitrary number of parameters, if it is the first call to #resume then they will be passed as block arguments. Otherwise they will be the return value of the call to Fiber.yield

Example:

fiber = Fiber.new do |first|
  second = Fiber.yield first + 2
end

puts fiber.resume 10
puts fiber.resume 1_000_000
puts fiber.resume "The fiber will be dead before I can cause trouble"

produces

12
1000000
FiberError: dead fiber called

Direct Known Subclasses

Pool

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(*args) ⇒ Object

:nodoc:



1779
1780
1781
1782
1783
# File 'cont.c', line 1779

static VALUE
rb_fiber_initialize(int argc, VALUE* argv, VALUE self)
{
    return fiber_initialize(self, rb_block_proc(), &shared_fiber_pool);
}

Class Method Details

.currentObject

Returns the current fiber. You need to require 'fiber' before using this method. If you are not running in the context of a fiber this method will return the root fiber.



2279
2280
2281
2282
2283
# File 'cont.c', line 2279

static VALUE
rb_fiber_s_current(VALUE klass)
{
    return rb_fiber_current();
}

.yield(args, ...) ⇒ Object

Yields control back to the context that resumed the fiber, passing along any arguments that were passed to it. The fiber will resume processing at this point when #resume is called next. Any arguments passed to the next #resume will be the value that this Fiber.yield expression evaluates to.

Returns:



2265
2266
2267
2268
2269
# File 'cont.c', line 2265

static VALUE
rb_fiber_s_yield(int argc, VALUE *argv, VALUE klass)
{
    return rb_fiber_yield_kw(argc, argv, PASS_KW_SPLAT);
}

Instance Method Details

#alive?Boolean

Returns true if the fiber can still be resumed (or transferred to). After finishing execution of the fiber block this method will always return false. You need to require 'fiber' before using this method.

Returns:

  • (Boolean)


2142
2143
2144
2145
2146
# File 'cont.c', line 2142

VALUE
rb_fiber_alive_p(VALUE fiber_value)
{
    return FIBER_TERMINATED_P(fiber_ptr(fiber_value)) ? Qfalse : Qtrue;
}

#raiseObject #raise(string) ⇒ Object #raise(exception[, string [, array]]) ⇒ Object

Raises an exception in the fiber at the point at which the last Fiber.yield was called, or at the start if neither resume nor raise were called before.

With no arguments, raises a RuntimeError. With a single String argument, raises a RuntimeError with the string as a message. Otherwise, the first parameter should be the name of an Exception class (or an object that returns an Exception object when sent an exception message). The optional second parameter sets the message associated with the exception, and the third parameter is an array of callback information. Exceptions are caught by the rescue clause of begin...end blocks.

Overloads:



2188
2189
2190
2191
2192
2193
# File 'cont.c', line 2188

static VALUE
rb_fiber_raise(int argc, VALUE *argv, VALUE fiber)
{
    VALUE exc = rb_make_exception(argc, argv);
    return rb_fiber_resume_kw(fiber, -1, &exc, RB_NO_KEYWORDS);
}

#resume(args, ...) ⇒ Object

Resumes the fiber from the point at which the last Fiber.yield was called, or starts running it if it is the first call to #resume. Arguments passed to resume will be the value of the Fiber.yield expression or will be passed as block parameters to the fiber’s block if this is the first #resume.

Alternatively, when resume is called it evaluates to the arguments passed to the next Fiber.yield statement inside the fiber’s block or to the block value if it runs to completion without any Fiber.yield

Returns:



2163
2164
2165
2166
2167
# File 'cont.c', line 2163

static VALUE
rb_fiber_m_resume(int argc, VALUE *argv, VALUE fiber)
{
    return rb_fiber_resume_kw(fiber, argc, argv, PASS_KW_SPLAT);
}

#to_sString Also known as: inspect

Returns fiber information string.

Returns:



2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
# File 'cont.c', line 2293

static VALUE
fiber_to_s(VALUE fiber_value)
{
    const rb_fiber_t *fiber = fiber_ptr(fiber_value);
    const rb_proc_t *proc;
    char status_info[0x20];

    if (fiber->transferred) {
        snprintf(status_info, 0x20, " (%s, transferred)", fiber_status_name(fiber->status));
    }
    else {
        snprintf(status_info, 0x20, " (%s)", fiber_status_name(fiber->status));
    }

    if (!rb_obj_is_proc(fiber->first_proc)) {
        VALUE str = rb_any_to_s(fiber_value);
        strlcat(status_info, ">", sizeof(status_info));
        rb_str_set_len(str, RSTRING_LEN(str)-1);
        rb_str_cat_cstr(str, status_info);
        return str;
    }
    GetProcPtr(fiber->first_proc, proc);
    return rb_block_to_s(fiber_value, &proc->block, status_info);
}

#transfer(args, ...) ⇒ Object

Transfer control to another fiber, resuming it from where it last stopped or starting it if it was not resumed before. The calling fiber will be suspended much like in a call to Fiber.yield. You need to require 'fiber' before using this method.

The fiber which receives the transfer call is treats it much like a resume call. Arguments passed to transfer are treated like those passed to resume.

You cannot call resume on a fiber that has been transferred to. If you call transfer on a fiber, and later call resume on the the fiber, a FiberError will be raised. Once you call transfer on a fiber, the only way to resume processing the fiber is to call transfer on it again.

Example:

fiber1 = Fiber.new do
  puts "In Fiber 1"
  Fiber.yield
  puts "In Fiber 1 again"
end

fiber2 = Fiber.new do
  puts "In Fiber 2"
  fiber1.transfer
  puts "Never see this message"
end

fiber3 = Fiber.new do
  puts "In Fiber 3"
end

fiber2.resume
fiber3.resume
fiber1.resume rescue (p $!)
fiber1.transfer

produces

In Fiber 2
In Fiber 1
In Fiber 3
#<FiberError: cannot resume transferred Fiber>
In Fiber 1 again

Returns:



2247
2248
2249
2250
2251
2252
2253
# File 'cont.c', line 2247

static VALUE
rb_fiber_m_transfer(int argc, VALUE *argv, VALUE fiber_value)
{
    rb_fiber_t *fiber = fiber_ptr(fiber_value);
    fiber->transferred = 1;
    return fiber_switch(fiber, argc, argv, 0, PASS_KW_SPLAT);
}