"Creating and spawning a thread can be factored out into two separate steps:"
{ $subsection <thread> }
{ $subsection (spawn) }
"Threads stop either when the quotation given to " { $link spawn } " returns, or when the following word is called:"
{ $subsection stop }
"If the image is saved and started again, all runnable threads are stopped. Vocabularies wishing to have a background thread always running should use " { $link add-init-hook } ".";
ARTICLE: "threads-yield""Yielding and suspending threads"
"Threads can be suspended and woken up at some point in the future when a condition is satisfied:"
{ $subsection suspend }
{ $subsection resume }
{ $subsection resume-with } ;
ARTICLE: "thread-state""Thread-local state"
"Threads form a class of objects:"
{ $subsection thread }
"The current thread:"
{ $subsection self }
"Thread-local variables:"
{ $subsection tnamespace }
{ $subsection tget }
{ $subsection tset }
{ $subsection tchange }
"Global hashtable of all threads, keyed by " { $link thread-id } ":"
{ $subsection threads }
"Threads have an identity independent of continuations. If a continuation is refied in one thread and then resumed in another thread, the code running in that continuation will observe a change in the value output by " { $link self } ".";
"Factor supports lightweight co-operative threads implemented on top of continuations. A thread will yield while waiting for input/output operations to complete, or when a yield has been explicitly requested."
$nl
"Factor threads are very lightweight. Each thread can take as little as 900 bytes of memory. This library has been tested running hundreds of thousands of simple threads."
{ $description "Low-level thread constructor. The thread runs the quotation when spawned; the name is simply used to identify the thread for debugging purposes. The error handler is called if the thread's quotation throws an unhandled error; it should either print the error or notify another thread." }
{ $notes "In most cases, user code should call " { $link spawn } " instead, however for control over the error handler quotation, threads can be created with " { $link <thread> } " then passed to " { $link (spawn) } "." } ;
HELP:run-queue
{ $values { "queue" dlist } }
{ $var-description "Global variable holding the queue of runnable threads. Calls to " { $link yield } " switch to the thread which has been in the queue for the longest period of time."
$nl
"By convention, threads are queued with " { $link push-front }
" and dequeued with " { $link pop-back } "." } ;
HELP:resume
{ $values { "thread" thread } }
{ $description "Adds a thread to the end of the run queue. The thread must have previously been suspended by a call to " { $link suspend } "." } ;
HELP:resume-with
{ $values { "obj"object } { "thread" thread } }
{ $description "Adds a thread to the end of the run queue together with an object to pass to the thread. The thread must have previously been suspended by a call to " { $link suspend } "; the object is returned from the " { $link suspend } " call." } ;
HELP:sleep-queue
{ $var-description "A " { $link min-heap } " storing the queue of sleeping threads." } ;
HELP:sleep-time
{ $values { "ms""a non-negative integer or " { $link f } } }
{ $description "Outputs the time until the next sleeping thread is scheduled to wake up, which could be zero if there are threads in the run queue, or threads which need to wake up right now. If there are no runnable or sleeping threads, outputs " { $link f } "." } ;
HELP:stop
{ $description "Stops the current thread. The thread may be started again from another thread using " { $link (spawn) } "." } ;
HELP:yield
{ $description "Adds the current thread to the end of the run queue, and switches to the next runnable thread." } ;
{ $description "Suspends the current thread for " { $snippet "ms" } " milliseconds." }
{ $errors "Throws an error if another thread interrupted the sleep with " { $link interrupt } "." } ;
HELP:nap
{ $values { "ms/f""a non-negative integer or " { $link f } } { "?""a boolean indicating whether the thread was interrupted" } }
{ $description "Suspends the current thread until another thread interrupts it with " { $link interrupt } ". If the input parameter is not " { $link f } ", then the thread will also wake up if the timeout expires before an interrupt is received." } ;
HELP:interrupt
{ $values { "thread" thread } }
{ $description "Interrupts a sleeping thread." } ;
{ $description "Suspends the current thread and passes it to the quotation. After the quotation returns, control yields to the next runnable thread and the current thread does not execute again until it is resumed, and so the quotation must arrange for another thread to later resume the suspended thread with a call to " { $link resume } " or " { $link resume-with } "." } ;
HELP:spawn
{ $values { "quot" quotation } { "name"string } }
{ $description "Spawns a new thread. The thread begins executing the given quotation; the name is for debugging purposes. The new thread begins running immediately and the current thread is added to the end of the run queue."
"The new thread begins with an empty data stack, an empty catch stack, and a name stack containing the global namespace only. This means that the only way to pass data to the new thread is to explicitly construct a quotation containing the data, for example using " { $link curry } " or " { $link compose } "." }
{ $description "Convenience wrapper around " { $link spawn } " which repeatedly calls the quotation in a new thread until it outputs " { $link f } "." }
{ $examples
"A thread that runs forever:"
{ $code "[ do-foo-bar t ] \"Foo bar server\" spawn-server" }