The latest 1.0.6 build has a functioning threading API.
The thread lifecycle is composed of three states:
New: a Thread has been created via Thread.make, but not yet started
Running: a thread is actively running
Dead: the thread has been stopped
The first two states New and Running are the Active state which means the thread:
Is globally mapped by name
Thread.find will find it
Thread.list will list it Once the Thread enters the dead state it is no longer mapped by name.
A thread is created with an optional name and an optional run method. If name is provided then it must be unique to the VM and that name can be used to lookup the thread via Thread.find. If name is not provided, then a name is auto generated. If run is provided, then it is the method invoked to execute the thread - otherwise you must subclass Thread and override the run() method. The run method must be const (it cannot capture any state of the creating thread) - however you can use a curry to pass in const parameters.
For Java runtime, I've implemented a self-tuning thread pool. Every Java thread which backs a sys::Thread lingers for 5 seconds after the sys::Thread stops, after which if no new sys::Threads have come along to reuse it, the Java thread dies.
There are two ways to communicate state between threads. The first way (the simple way) is to have the run method return an immutable object. This object will be returned from Thread.join if another thread blocks and waits for the thread to stop:
t := Thread.make(null, &doSomeBackgroundWork).start
doSomeOtherStuff
result := t.join
The more sophisticated way to communicate state is via messaging. Every thread has a message queue which may be used to send and receive messages. Currently these objects must be immutable objects - in the future we need to support serializable objects and probably IO pipes. You can send an async message (fire and forget) or you can send a sync message. A sync message will block the caller until the thread processes the message. The result is returned to the caller, or if an exception was raised processing the message that exception is raised to the caller. In all cases, the objects exchanged must be immutable which means they are thread safe without locking (Fan has no locking). This also required making Err const.
There are various approaches to flow control, but for now I chose a simple mechanism. Every thread has a max queue size. If an attempt is made to post a message via either sendSync or sendAsync to a full queue, then the calling thread is blocked until there is space on the queue. In the future we probably want a more sophisticated approach to flow control - maybe with some deadlock detection.
Threads which wish to process their message queue, must provide a run method which enters a main loop via the Thread.loop method. The loop method takes a receive callback, which is invoked whenever a message is ready to be processed. A simple messaging example:
I relaxed the rules on value returned by the run() method - it no longer has be immutable. But only the first thread who joins can receive the value. This is a safe way to pass a non-immutable data between threads, and will probably be common when spawning a thread to compute some data structure. For example, I might use this to spawn a thread in the compiler to parse each source file, then return the ASTs back to the main thread.
brian Tue 6 Feb 2007
The latest 1.0.6 build has a functioning threading API.
The thread lifecycle is composed of three states:
The first two states New and Running are the Active state which means the thread:
A thread is created with an optional name and an optional run method. If name is provided then it must be unique to the VM and that name can be used to lookup the thread via Thread.find. If name is not provided, then a name is auto generated. If run is provided, then it is the method invoked to execute the thread - otherwise you must subclass Thread and override the run() method. The run method must be const (it cannot capture any state of the creating thread) - however you can use a curry to pass in const parameters.
For Java runtime, I've implemented a self-tuning thread pool. Every Java thread which backs a sys::Thread lingers for 5 seconds after the sys::Thread stops, after which if no new sys::Threads have come along to reuse it, the Java thread dies.
There are two ways to communicate state between threads. The first way (the simple way) is to have the run method return an immutable object. This object will be returned from Thread.join if another thread blocks and waits for the thread to stop:
The more sophisticated way to communicate state is via messaging. Every thread has a message queue which may be used to send and receive messages. Currently these objects must be immutable objects - in the future we need to support serializable objects and probably IO pipes. You can send an async message (fire and forget) or you can send a sync message. A sync message will block the caller until the thread processes the message. The result is returned to the caller, or if an exception was raised processing the message that exception is raised to the caller. In all cases, the objects exchanged must be immutable which means they are thread safe without locking (Fan has no locking). This also required making Err const.
There are various approaches to flow control, but for now I chose a simple mechanism. Every thread has a max queue size. If an attempt is made to post a message via either sendSync or sendAsync to a full queue, then the calling thread is blocked until there is space on the queue. In the future we probably want a more sophisticated approach to flow control - maybe with some deadlock detection.
Threads which wish to process their message queue, must provide a run method which enters a main loop via the Thread.loop method. The loop method takes a receive callback, which is invoked whenever a message is ready to be processed. A simple messaging example:
brian Sun 11 Feb 2007
I relaxed the rules on value returned by the run() method - it no longer has be immutable. But only the first thread who joins can receive the value. This is a safe way to pass a non-immutable data between threads, and will probably be common when spawning a thread to compute some data structure. For example, I might use this to spawn a thread in the compiler to parse each source file, then return the ASTs back to the main thread.