[ Engines and Threads | Reference Manual | Alphabetic Index ]

yield(+ToParent, -FromParent)

Stop the running engine in the yielded-state, and wait for resume
ToParent
A term to be passed to the parent.
FromParent
A variable to be unified with term from parent.

Description

All ECLiPSe code is executed by an ECLiPSe engine. This engine can be invoked from a parent program, which is either in a different language (C/C++, Tcl, Java), or is itself an ECLiPSe program. In either case, the interaction between the ECLiPSe engine and the parent execution follows a resume-yield model of control flow: the parent execution transfers control to the engine via a 'resume' operation, and the engine returns control via a 'yield' operation. There are implicit yield operations (such as when the engine execution succeeds, fails or aborts), but the yield/2 predicate provides an explicit way of transferring control.

An engine that executes the yield/2 predicate stops executing, enters the yielded-state, and waits until it is resumed again.

Data can be passed both ways: the ToParent argument is passed from the engine to a parent on yielding, the FromParent argument receives a term from the parent on resumption.

Synchronous Operation

Synchronous operation means that the engine was resumed via the engine_resume/3 predicate (if the resumer is ECLiPSe code), or one of the corresponding primitives in one of the foreign language interfaces (e.g. ec_resume()). In response to a yield/2, the resume-primitive returns, and the status code yielded(ToParent) is passed from the yielding engine to its resumer.

If the engine is resumed again later (e.g. with another call to engine_resume/3), the yield/2 predicate inside the engine succeeds, and engine execution continues. The second argument of engine_resume/3 (FromParent) is passed from the resumer to the engine, and unified with the second argument of yield/2 before engine execution continues.

Asynchronous Operation

Asynchronous operation means that the engine was resumed via the engine_resume_thread/2 predicate (if the resumer is ECLiPSe code), or one of the corresponding primitives in one of the foreign language interfaces (e.g. ec_resume_async()). In this case, the engine runs in its own thread, and in response to a yield/2 another thread can join the engine (engine_join/3), pick up the yielded(ToParent) status, and possibly resume the engine again later.

Modes and Determinism

Examples

% Communication between engines (synchronous)

    ?- engine_create(E, []),
       engine_resume(E, (
                yield(message_to_parent,From),
                writeln(received(From))
            ), S1),
       engine_resume(E, message_from_parent, S2).

    received(message_from_parent)

    E = $&(engine,"376oe7")
    S1 = yielded(message_to_parent)
    S2 = true
    Yes (0.00s cpu)


% Communication between engines (asynchronous)

    ?- engine_create(E, []),
       engine_resume_thread(E, (
                yield(message_to_parent,From),
                writeln(received(From))
            )),
       engine_join(E, block, S1),
       engine_resume_thread(E, message_from_parent),
       engine_join(E, block, S2).

    received(message_from_parent)

    E = $&(engine,"376oe7")
    S1 = yielded(message_to_parent)
    S2 = true
    Yes (0.00s cpu)



% Embedding situation: ECLiPSe server code

    start_server :-
        eclipse_server(dummy).

    eclipse_server(PrevResult) :-
        yield(PrevResult, Request),
        process_request(Request, NewResult),
        eclipse_server(NewResult).


    // C++ client code
    ec_init();
    post_goal("start_server");
    if (EC_resume() == EC_yield)
    {
        for(;;)
        {
            // create a request
            ...
            if (EC_resume(request, result) != EC_yield);
                break;
            ...
            // use the result
        }
    }

See Also

engine_resume / 3, engine_resume_thread / 2, engine_join / 3, get_engine_property / 3