|
NAME
| |
alt, chancreate, chanfree, chaninit, chanprint, chansetname, mainstacksize,
proccreate, procdata, recv, recvp, recvul, send, sendp, sendul,
nbrecv, nbrecvp, nbrecvul, nbsend, nbsendp, nbsendul, threadcreate,
threaddata, threadexec, threadexecl, threadexits, threadexitsall,
threadgetgrp, threadgetname, threadint,
threadintgrp, threadkill, threadkillgrp, threadmain, threadnotify,
threadid, threadpid, threadsetgrp, threadsetname, threadsetstate,
threadspawn, threadwaitchan, yield – thread and proc management
|
SYNOPSIS
| |
#include <u.h>
#include <libc.h>
#include <thread.h>
#define CHANEND 0
#define CHANSND 1
#define CHANRCV 2
#define CHANNOP 3
#define CHANNOBLK 4
typedef struct Alt Alt;
struct Alt {
| |
Channel *c;
void *v;
int op;
Channel **tag;
int entryno;
char *name;
|
};
void threadmain(int argc, char *argv[])
int mainstacksize
int proccreate(void (*fn)(void*), void *arg, uint stacksize)
int threadcreate(void (*fn)(void*), void *arg, uint stacksize)
void threadexits(char *status)
void threadexitsall(char *status)
void yield(void)
int threadid(void)
int threadgrp(void)
int threadsetgrp(int group)
int threadpid(int id)
int threadint(int id)
int threadintgrp(int group)
int threadkill(int id)
int threadkillgrp(int group)
void threadsetname(char *name)
char* threadgetname(void)
void** threaddata(void)
void** procdata(void)
int chaninit(Channel *c, int elsize, int nel)
Channel* chancreate(int elsize, int nel)
void chanfree(Channel *c)
int alt(Alt *alts)
int recv(Channel *c, void *v)
void* recvp(Channel *c)
ulong recvul(Channel *c)
int nbrecv(Channel *c, void *v)
void* nbrecvp(Channel *c)
ulong nbrecvul(Channel *c)
int send(Channel *c, void *v)
int sendp(Channel *c, void *v)
int sendul(Channel *c, ulong v)
int nbsend(Channel *c, void *v)
int nbsendp(Channel *c, void *v)
int nbsendul(Channel *c, ulong v)
int chanprint(Channel *c, char *fmt, ...)
int threadspawn(int fd[3], char *file, char *args[])
int threadexecl(Channel *cpid, int fd[3], char *file, ...)
int threadexec(Channel *cpid, int fd[3], char *file, char *args[])
Channel* threadwaitchan(void)
int threadnotify(int (*f)(void*, char*), int in)
|
DESCRIPTION
| |
The thread library provides parallel programming support similar
to that of the languages Alef and Newsqueak. Threads and procs
occupy a shared address space, communicating and synchronizing
through channels and shared variables.
A proc is a Plan 9 process that contains one or more cooperatively
scheduled threads. Programs using threads must replace main by
threadmain. The thread library provides a main function that sets
up a proc with a single thread executing threadmain on a stack
of size mainstacksize (default eight kilobytes). To set
mainstacksize, declare a global variable initialized to the desired
value (e.g., int mainstacksize = 1024).
Threadcreate creates a new thread in the calling proc, returning
a unique integer identifying the thread; the thread executes fn(arg)
on a stack of size stacksize. Thread stacks are allocated in shared
memory, making it valid to pass pointers to stack variables between
threads and procs. Proccreate creates a new proc,
and inside that proc creates a single thread as threadcreate would,
returning the id of the created thread. Be aware that the calling
thread may continue execution before the newly created proc and
thread are scheduled. Because of this, arg should not point to
data on the stack of a function that could return before the
new process is scheduled.
Threadexits terminates the calling thread. If the thread is the
last in its proc, threadexits also terminates the proc, using
status as the exit status. Threadexitsall terminates all procs
in the program, using status as the exit status.
When the last thread in threadmain’s proc exits, the program will
appear to its parent to have exited. The remaining procs will
still run together, but as a background program.
The threads in a proc are coroutines, scheduled nonpreemptively
in a round-robin fashion. A thread must explicitly relinquish
control of the processor before another thread in the same proc
is run. Calls that do this are yield, proccreate, threadexec,
threadexecl, threadexits, threadspawn, alt, send, and recv (and
the
calls related to send and recv--see their descriptions further on).
Procs are scheduled by the operating system. Therefore, threads
in different procs can preempt one another in arbitrary ways and
should synchronize their actions using qlocks (see lock(3)) or
channel communication. System calls such as read(3)
block the entire proc; all threads in a proc block until the system
call finishes.
As mentioned above, each thread has a unique integer thread id.
Thread ids are not reused; they are unique across the life of
the program. Threadid returns the id for the current thread. Each
thread also has a thread group id. The initial thread has a group
id of zero. Each new thread inherits the group id of the
thread that created it. Threadgrp returns the group id for the
current thread; threadsetgrp sets it. Threadpid returns the pid
of the Plan 9 process containing the thread identified by id,
or –1 if no such thread is found.
Threadint interrupts a thread that is blocked in a channel operation
or system call. Threadintgrp interrupts all threads with the given
group id. Threadkill marks a thread to die when it next relinquishes
the processor (via one of the calls listed above). If the thread
is blocked in a channel operation or system call, it is
also interrupted. Threadkillgrp kills all threads with the given
group id. Note that threadkill and threadkillgrp will not terminate
a thread that never relinquishes the processor.
Primarily for debugging, threads can have string names associated
with them. Threadgetname returns the current thread’s name; threadsetname
sets it. The pointer returned by threadgetname is only valid until
the next call to threadsetname.
Also for debugging, threads have a string state associated with
them. Threadsetstate sets the state string. There is no threadgetstate;
since the thread scheduler resets the state to Running every time
it runs the thread, it is only useful for debuggers to inspect
the state.
Threaddata returns a pointer to a per-thread pointer that may
be modified by threaded programs for per-thread storage. Similarly,
procdata returns a pointer to a per-proc pointer.
Threadexecl and threadexec are threaded analogues of exec and
execl (see exec(3)); on success, they replace the calling thread
and invoke the external program, never returning. (Unlike on Plan
9, the calling thread need not be the only thread in its proc--the
other threads will continue executing.) On error, they return
–1. If cpid is not null, the pid of the invoked program will be
sent along cpid (using sendul) once the program has been started,
or –1 will be sent if an error occurs. Threadexec and threadexecl
will not access their arguments after sending a result along cpid.
Thus, programs that malloc the argv passed to threadexec
can safely free it once they have received the cpid response.
Threadexecl and threadexec will duplicate (see dup(3)) the three
file descriptors in fd onto standard input, output, and error
for the external program and then close them in the calling thread.
Beware of code that sets
| |
fd[0] = 0;
fd[1] = 1;
fd[2] = 2;
|
to use the current standard files. The correct code is
| |
fd[0] = dup(0, −1);
fd[1] = dup(1, −1);
fd[2] = dup(2, −1);
|
Threadspawn is like threadexec but does not replace the current
thread. It returns the pid of the invoked program on success,
or –1 on error.
Threadwaitchan returns a channel of pointers to Waitmsg structures
(see wait(3)). When an exec’ed process exits, a pointer to a Waitmsg
is sent to this channel. These Waitmsg structures have been allocated
with malloc(3) and should be freed after use.
A Channel is a buffered or unbuffered queue for fixed-size messages.
Procs and threads send messages into the channel and recv messages
from the channel. If the channel is unbuffered, a send operation
blocks until the corresponding recv operation occurs and vice
versa. Chaninit initializes a Channel for
messages of size elsize and with a buffer holding nel messages.
If nel is zero, the channel is unbuffered. Chancreate allocates
a new channel and initializes it. Chanfree frees a channel that
is no longer used. Chanfree can be called by either sender or
receiver after the last item has been sent or received. Freeing
the
channel will be delayed if there is a thread blocked on it until
that thread unblocks (but chanfree returns immediately).
The name element in the Channel structure is a description intended
for use in debugging. Chansetname sets the name.
Send sends the element pointed at by v to the channel c. If v
is null, zeros are sent. Recv receives an element from c and stores
it in v. If v is null, the received value is discarded. Send and
recv return 1 on success, –1 if interrupted. Nbsend and nbrecv
behave similarly, but return 0 rather than blocking.
Sendp, nbsendp, sendul, and nbsendul send a pointer or an unsigned
long; the channel must have been initialized with the appropriate
elsize. Recvp, nbrecvp, recvul, and nbrecvul receive a pointer
or an unsigned long; they return zero when a zero is received,
when interrupted, or (for nbrecvp and nbrecvul) when the
operation would have blocked. To distinguish between these three
cases, use recv or nbrecv.
Alt can be used to recv from or send to one of a number of channels,
as directed by an array of Alt structures, each of which describes
a potential send or receive operation. In an Alt structure, c
is the channel; v the value pointer (which may be null); and op
the operation: CHANSND for a send operation,
CHANRECV for a recv operation; CHANNOP for no operation (useful
when alt is called with a varying set of operations). The array
of Alt structures is terminated by an entry with op CHANEND or
CHANNOBLK. If at least one Alt structure can proceed, one of them
is chosen at random to be executed. Alt returns the
index of the chosen structure. If no operations can proceed and
the list is terminated with CHANNOBLK, alt returns the index of
the terminating CHANNOBLK structure. Otherwise, alt blocks until
one of the operations can proceed, eventually returning the index
of the structure executes. Alt returns –1 when
interrupted. The tag and entryno fields in the Alt structure are
used internally by alt and need not be initialized. They are not
used between alt calls.
Chanprint formats its arguments in the manner of print(3) and
sends the result to the channel c. The string delivered by chanprint
is allocated with malloc(3) and should be freed upon receipt.
Thread library functions do not return on failure; if errors occur,
the entire program is aborted.
Threaded programs should use threadnotify in place of atnotify
(see notify(3)).
It is safe to use sysfatal(3) in threaded programs. Sysfatal will
print the error string and call threadexitsall.
It is not safe to call rfork in a threaded program, except to
call rfork(RFNOTEG) from the main proc before any other procs
have been created. To create new processes, use proccreate.
|
FILES
| |
/usr/local/plan9/acid/thread contains useful acid(1) functions
for debugging threaded programs.
/usr/local/plan9/src/libthread/test contains some example programs.
|
SOURCE
| |
/usr/local/plan9/src/libthread
|
SEE ALSO
BUGS
| |
To avoid name conflicts, alt, nbrecv, nbrecvp, nbrecvul, nbsend,
nbsendp, nbsendul, recv, recvp, recvul, send, sendp, and sendul
are defined as macros that expand to chanalt, channbrecv, and
so on. Yield is defined as a macro that expands to threadyield.
See intro(3).
The implementation of threadnotify may not be correct.
|
|
|