AT&T Home | AT&T Labs | Research
AT&T Labs, Inc. - Research

The Yoix® Scripting Language

Home | What's New | Grammar | Documentation | Download | License | YChart | YDAT | YWAIT | Byzgraf | FAQs
Thread typedict
 
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 callable, ...) 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 callable must be a function (or built-in) or a pointer to a function (or built-in), and everything that follows callable are arguments that are passed to the queued function when it reaches the head of the queue and is executed by the thread. queue complains with a badcall error if the function that is called requires a different number of arguments than were actually supplied. Queuing a function automatically starts a stopped thread.

If *callable is a function (or built-in) and callable itself is a Dictionary or any other object that associates names with values, then callable is used as the function's local context. In other words, callable will be used to resolve this and it will also be searched immediately before the function's global context.

queueOnce(Object callable, ...) A Builtin that behaves just like queue if it looks like callable 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

 

Yoix is a registered trademark of AT&T Inc.