A
Thread
represents a lightweight process that is implemented using Java's
Thread class.
Yoix applications can create and run new threads, but they are also used
to represent threads that the Java Virtual Machine starts.
In the latter case, most of the fields described below have permissions
that allow reading but not writing.
The fields in a
Thread
are:
| alive |
An
int
that is
1
when the thread is running and
0
otherwise.
A thread with nothing to do
(i.e., an empty queue and no running function) stops itself, unless
persistent
is non-zero.
Reading returns the current state.
Writing immediately sets the thread's state to the new value,
so storing
0
kills a running thread, and storing
1
starts a stopped thread.
| | daemon |
An
int
that is
1
when the thread is a daemon thread and
0
otherwise.
Reading returns the current daemon status.
Writing has absolutely no effect on a thread that is alive.
When
VM.exitmodel
is
1,
the interpreter tries to guess if the entire application should
be killed when the main thread runs out of things to do.
A visible window or running thread that was created by the application
and is not a daemon thread, means the application survives.
| | group |
A
String
that is the name of the thread's group when it is running, and
NULL
when it is not.
Writing is not allowed and will result in an
invalidaccess
error.
| | interrupted |
An
int
that is
1
when the thread has been interrupted and
0
otherwise.
An interrupted thread stops what its doing and moves on to the
next queued function, or quits when there is nothing in the queue
and
persistent
is
0.
Reading returns the current state.
Writing a non-zero value immediately interrupts the thread.
| | name |
A
String
used to identify the thread that is automatically generated when
name
is
NULL.
Reading returns the thread's current name.
Writing immediately sets the thread's name to the new value.
| | persistent |
An
int
that is
0
when a running thread with nothing left to do stops itself,
and
1
when the thread waits for more work to arrive.
| | priority |
An
int
that represents the thread's priority.
The value must be greater than or equal to
MIN_PRIORITY
and less than or equal to
MAX_PRIORITY,
which are defined in
yoix.thread.
Reading returns the current priority.
Writing immediately sets the thread's priority to the new value.
| | queue(Object funct, ...) |
A
Builtin
that is used to manipulate the thread's function queue.
A thread that defines a
run
function will not be able to execute the
queue
built-in.
Reading and writing are not allowed; both operations will result in an
invalidaccess
error.
No arguments returns a snapshot of the queue;
a
NULL
argument clears the queue.
Otherwise
funct
must be a function or built-in and everything that follows
funct
are arguments that are passed to
funct
when it reaches the head of the queue and is executed by the thread.
queue
complains with a
badcall
error if
funct
requires a different number of arguments than were actually supplied.
Queuing a function automatically starts a stopped thread.
| | queueOnce(Object funct, ...) |
A
Builtin
that behaves just like
queue
if it looks like
funct
and its arguments are not already queued or being run by the thread,
otherwise it does nothing and returns
NULL
to the caller.
| | queuesize |
A read-only
int
that provides the current count of elements in the thread queue.
A thread that defines a
run
function and so cannot execute the
queue
built-in will always have a
queuesize
of zero.
| | run(...) |
A
Function
that is either
NULL,
or a function that accepts zero or more arguments and is automatically
executed whenever the thread is started.
The
run
function can only be defined in the thread's declaration;
changing it at any other time will result in an
invalidaccess
error.
The thread can be started by explicitly calling
run
with an arbitrary number of arguments or by storing
1
in
alive,
which implicitly calls
run
with no arguments.
| | state |
An
int
that is
1
when the thread is the one that is currently being executed by the
Java Virtual Machine, and
0
otherwise.
Writing is not allowed and will result in an
invalidaccess
error.
|
Several permanent fields have not been documented and should not be
used in Yoix applications.
| |
| Example: |
Threads are important and not particularly hard to use,
so we are going to give several examples.
The first program,
import yoix.*.*;
VM.exitmodel = 1; // interpreter should guess
Thread t = {
int daemon = 1;
int persistent = 1;
run() {
int n;
for (n = 0; n < 10; n++) {
printf("looping: n=%d\n", n);
sleep(3);
}
exit(0);
}
};
t.run(); // start the thread
sleep(5);
printf("main thread is done\n");
prints something like,
looping: n=0
looping: n=1
main thread is done
on standard output, because
VM.exitmodel
is
1
(the default) and we created a daemon thread, so the interpreter
exits when the main thread is finished.
However, set
daemon
to
0
and run the program again and 10 loopings will print before the
interpreter exits.
Our second example shows how functions are queued,
and what happens when fields like
interrupted
and
alive
are used.
Run the program,
import yoix.*.*;
f(arg) {
while (TRUE) {
printf("Function f, thread %s, arg=%.3f\n", name, arg);
sleep(1);
}
}
g() {
while (TRUE) {
printf("Function g, thread %s\n", name);
sleep(1);
}
}
Thread t;
t.queue(f, time());
t.queue(g);
sleep(2);
t.interrupted = TRUE;
sleep(2);
t.interrupted = TRUE;
sleep(2);
t.queue(f, time());
sleep(2);
t.alive = FALSE;
sleep(2);
t.queue(g);
sleep(2);
exit(0);
and something like,
Function f, thread YoixThread-1, arg=969126229.854
Function f, thread YoixThread-1, arg=969126229.854
Function g, thread YoixThread-1
Function g, thread YoixThread-1
Function f, thread YoixThread-1, arg=969126235.937
Function f, thread YoixThread-1, arg=969126235.937
Function g, thread YoixThread-1
Function g, thread YoixThread-1
Function g, thread YoixThread-1
prints on standard output.
Our last example is instructive, but it is not something you should copy.
Run the program,
import yoix.*.*;
Object lock1 = "lock1";
Object lock2 = "lock2";
Thread thread1 = {
run() {
synchronized(lock1) {
printf("thread1: got lock1\n");
sleep(3);
printf("thread1: waiting for lock2\n");
synchronized(lock2) {
printf("thread1: got lock2 - impossible\n");
sleep(5);
}
printf("thread1: released lock2\n");
}
printf("thread1: released lock1\n");
}
};
Thread thread2 = {
run() {
synchronized(lock2) {
printf("thread2: got lock2\n");
sleep(3);
printf("thread2: waiting for lock1\n");
synchronized(lock1) {
printf("thread2: got lock1 - impossible\n");
sleep(5);
}
printf("thread2: released lock1\n");
}
printf("thread2: released lock2\n");
}
};
thread1.run();
thread2.run();
and all you get is something like,
thread2: got lock2
thread1: got lock1
thread2: waiting for lock1
thread1: waiting for lock2
on standard output.
The program is in deadlock, which is definitely something you
do not want to happen to your programs.
| | |
| See Also: |
activeCount,
currentThread,
enumerate,
notifyAll,
sleep,
wait,
yield
|
|