Parallel agent main class.
Class Thread from \ Waitable( )
The Thread class controls the execution of parallel agents in the Falcon threading model.
The applicaiton willing to launch parallel agents should either derive the logical agent from the Thread class, or assign the run method of a Thread instance to a function of choice.
In example, both the following methods are valid:
class MyThread from Thread function run() > "Hello from the thread" end end function parallel( param ) > "Parallel called from another thread with ", param end // launching a thread using OOP inheritance... mt = MyThread() mt.start() // ... or using functional overload th = Thread() th.run = [parallel, "A parameter" ] th.start()
The static method Threading.start can be used to call an arbitrary function without encapsulating it in a Thread instance. The Threading class provides a set of static methods that can be used both by Thread instances and plain parallel code which has not been encapsulated in a instance of a class derived from Thread.
The Thread.start method will create a new system thread and a new Virtual Machine, configured as the machine in which it was called, but completely empty. The instance that is going to be started will be copied (via serialization) to the new Virtual Machine, and if the operation can be completed, the new Virtual Machine will execute the Thread.run method of the transferred instance.
As the new copy of the VM is clean, global objects and results of former elaboration in the calling VM are not available to the newborn thread, unless they are passed as members of the derived class or as parameters of the run deferred call.
This means that any synchronization structure needed for the thread must be set in the thread subclass instance (or in the parameters of the deferred call to run) before the thread is started. If provided with suitable structures that can transfer data to different threads, more data can be exchanged at a later time.
Methods | |
detach | Disengage this threads from waits and garbage. |
detached | Returns true if the target thread is detached. |
getError | Get the error that cause a thread to terminate, if any. |
getName | Sets the symbolic name of this thread. |
getReturn | Get the return value that was returned by the thread main function. |
getSystemID | Gets the system low level thread ID for this thread. |
getThreadID | Gets an unique numeric ID for this thread. |
hadError | Returns true if the target thread was terminated because of an uncaught raised item. |
join | Waits for a thread to terminate and returns its return value. |
run | Overloading hook that will hold the thread main function. |
sameThread | Returns true if the givevn thread is running the same thread as this object. |
setName | Sets the symbolic name of this thread. |
start | Launches the thread in a parallel environment. |
stop | Interrupts the target thread. |
terminated | Returns true if the target thread is terminated. |
toString | Returns a string representation of this thread. |
vwait | Wait for one or more synchronization strucures to become available. |
wait | Wait for one or more synchronization strucures to become available. |
Methods inherited from class Waitable | |
release | Releases a structure acquired by a waiting function. |
Disengage this threads from waits and garbage.
Thread.detach()
This method sets the thread for which it has been called in "detached" status. This means that the thread will just run in background for the rest of the application life, or for how long it needs, and the main application doesn't want to be notified about the thread termination, nor to control its behavior anymore.
The net effect is that the thread is free to run as long as the application is alive. The VM running the thread is not bound anymore to the calling VM, and stopping and destroying the calling VM will have no effect on the thread.
Normally, when the thread object is garbage collected, or when the calling VM is destroyed and its garbage freed, the collector joins the system thread before destroying the Falcon thread instance. In other words, the destructor will wait for the target thread to terminate naturally.
By detaching the thread, the caller signals that it doesn't want to use this thread object anymore, and that the system thread associated with this instance is free to run beyond the lifetime of this Falcon item.
As a side effect, it is not anymore possible to join this thread; threads eventually waiting for this thread to end will receive a JoinError, as threds trying to wait for its termination after that detach has been called.
The detached state is not reversible. Once detached, a thread is left to its own destiny. However, it's still possible to communicate to it through synchronization structures and through methods in this instance, as i.e. Thread.stop.
Returns true if the target thread is detached.
Thread.detached()
Return | True if the thread has been detached, false otherwise. |
Get the error that cause a thread to terminate, if any.
Thread.getError()
Return | nil if the thread terminated correctly, the error that caused thread termination otherwise. | ||
Raise |
|
This method return the item that was raised by a thread and that wasn't caught at thread toplevel. If a thread terminated because of an unhandled error, and not because of a clean exit from the run method, this method will return the raised item, which is usually an item of class Error.
Sets the symbolic name of this thread.
Thread.getName()
Return | A string containing the name of this thread (may be empty if not set). |
Get the return value that was returned by the thread main function.
Thread.getReturn()
Return | The value returned by the thread main fucntion. | ||
Raise |
|
This method return the item that was returned by the main thread function, wihch is the Thread.run method. If the thread terminated without returning any value, nil will be returned.
Note: The caller should ascertain that the thread wasn't terminated by an uncaught error with Thread.hadError before to call this method.
Note: The value retreived is actually a local copy of the value returned by the terminated thread. Changing it won't affect other threads willing to read the original value. Also, if the returned value is not serializable, this method will raise a CodeError.
Gets the system low level thread ID for this thread.
Thread.getSystemID()
Return | A numeric thread ID. |
UThis is the system ID for the thread that is being run in the target Falcon object; for those systems that doesn't provide a numeric thread ID, this method returns a pointer to the system resources identifying the thread (as an integer value). It is always granted that two different living threads have different identifiers, but a thread ID may be re-assigned to newly started threads after previous one are dead.
If the thread isn't started, the method returns a meaningless number.
Gets an unique numeric ID for this thread.
Thread.getThreadID()
Return | A numeric thread ID. |
This is an unique counter assigned to each thread as they are created.
Returns true if the target thread was terminated because of an uncaught raised item.
Thread.hadError()
Return | True if the thread was terminated because of an uncaught raise, false if it terminated correctly. | ||
Raise |
|
Waits for a thread to terminate and returns its return value.
Thread.join()
Return | The exit value of the target thread. | ||||
Raise |
|
This method is actually a shortcut for waiting the thread to become acquireable, and then checking for its termination value. Unless it can be proven that this is the only thread interested to the exit value of the thread to be joined, it is preferrable to use the Thread.wait method, and then checking the return value of the target thread with Thread.getReturn.
If the thread cannot be acquired after termination because it has been detached, this method will raise a JoinError. If the target thread exits with error (raises an item at toplevel) this method raises a ThreadError, and the item raised by the target thread is set as "next" error in the raised ThreadError.
Note: This method doesn't use system level "join" call or equivalent. Falcon calls join(), or equivalent means to dispose of the system-level thread resources only at garbage collecting, or in case a thread instance is used to start another thread after termination. In other words, it is NOT necessary to call this join method on threads started through this API.
Overloading hook that will hold the thread main function.
Thread.run()
Return | A value that will be available for inspection in other threads. |
This method is called by the new thread when the Thread.start method is called. The new thread executes the function in run(), and when the function returns, the thread is terminated.
Other threads may wait for this thread to terminate through one of the Waitings
The value returned by this method is made available to inspecting threads through serialization.
Returns true if the givevn thread is running the same thread as this object.
Thread.sameThread( otherThread )
otherThread | Another thread to be checked against. |
Return | True if the system thread running in this Falcon objects are the same. |
Sets the symbolic name of this thread.
Thread.setName( name )
name | The new name for this thread. |
See also: Thread.
Launches the thread in a parallel environment.
Thread.start()
Raise |
|
This method checks for this instance to have a runnable Thread.run method, and then for this object to be fully serializable. Once the instance is readied to be transferred to a parallel environment, the method crates a new Virtual Machine, linking all the modules that are linked to the VM where the start method is called.
Finally, the instance is transferred to the other VM, de-serialized there and readied for execution. When everything is ready, the new thread is finally started and the run method is executed in the parallel environment.
This method represents a single point of discontinuity in the calling application. On failure, an error is raised, reporting the details of the problem. Problems preventing parallel execution may be due to system resources (i.e. limited thread handles or memory limits) or to programming error (i.e. having one of the properties in this instance being a complex object that cannot be serialized).
On success, the method return and the other thread is started immediately, or as soon as the system is able to start it.
If this object is connected to an already running thread, trying to start it will raise a ThreadError.
It is possible to start again the thread after it has terminated and joined, provided this is not a detached thread.
Interrupts the target thread.
Thread.stop()
This method sends a kind request for wait interruption to the VM running the target thread. The VM interruption request will stop waiting calls and raise an InterruptedError in the target thread. The thread may either honor the request and terminate as soon as it can or discard the signalation and resume normal execution.
Returns true if the target thread is terminated.
Thread.terminated()
Return | True if the thread is terminated, false otherwise. |
The method will return true if the target thread is not running anymore, either because of a correct terminationor because of an error.
Returns a string representation of this thread.
Thread.toString()
Return | A string containing anagraphic data for this thread. |
See also: Thread.
Wait for one or more synchronization strucures to become available.
Thread.vwait( structArray, [waitTime] )
structArray | Array of structures to wait for | ||
waitTime | Maximum timeout in seconds and fractions. | ||
Return | nil if timeout expires, an ID in the structArray or the acquired structure. | ||
Raise |
|
This method waits for one of the structures in the given structArray to become acquireable, and acquires it before returning.
This works exactly as Thread.wait, but, on success, the method returns the ID of the acquired item in structArray rather than the object itself. In this way, it is possible to rotate or change the list of items on which to wait for at each call.
See also: Thread.
Wait for one or more synchronization strucures to become available.
Thread.wait( ..., [waitTime] )
... | One or more synchronization structure to wait for. | ||
waitTime | Maximum timeout in seconds and fractions. | ||
Return | nil if timeout expires, or the acquired item on success. | ||
Raise |
|
This method waits for one of the structures in the given parameters to become acquireable, and acquires it before returning.
The acquired structure must be released manually after the thread has used the shared resource.
Typical usage pattern is that of acquiring the needed structures in the thread main loop, work with the achieved structure and release it. Also, it is useful to test for interruption and eventually honor the interruption request as soon as possibile:
class MyThread from Thread ... function run() loop try // wait at max 1 second. res = self.wait( resA, resB, 1.0 ) catch InterruptedError // honor the request return end // what are we up to? switch res case nil // timed out; perform some periodic operations case resA // do things with resA resA.release() case resB // do things with resB resB.release() end // do extra work with signaled data (*) end end end
The method tries to acquire the resource in the same order they are passed as paramters. If the first resource is always available when the thread enters the wait, this will actually prevent the thread from acquiring other resources. As some resources can be acquired relatively often, it is necessary to be careful about this aspect. Repeated acquisition and release may cause starving of other threads and of other resources being in need of handling.
It is advisable to release the resources as soon as possible and perform work on the shared data after they have been release, in the code section marked with (*). Also, if the structured waited on may become available at the same time, it is advisable to use Thread.vwait instead, to easily rotate the order in which the call tries to acquire the resources.
See also: Threading.