THREAD(2)THREAD(2)
NAME
alt,
chanclose,
chancreate,
chanfree,
chanclosing,
chanprint,
mainstacksize,
proccreate,
procdata,
procexec,
procexecl,
procrfork,
recv,
recvp,
recvul,
send,
sendp,
sendul,
nbrecv,
nbrecvp,
nbrecvul,
nbsend,
nbsendp,
nbsendul,
threadcreate,
threaddata,
threadexits,
threadexitsall,
threadgetgrp,
threadgetname,
threadint,
threadintgrp,
threadkill,
threadkillgrp,
threadmain,
threadnotify,
threadid,
threadpid,
threadsetgrp,
threadsetname,
threadwaitchan,
yield – thread and proc management
SYNOPSIS
#include <u.h>
#include <libc.h>
#include <thread.h>
unhandled troff command .sp
typedef enum {
CHANEND,
CHANSND,
CHANRCV,
CHANNOP,
CHANNOBLK,
} ChanOp;
unhandled troff command .sp
typedef struct Alt Alt;
struct Alt {
Channel *c; /* channel */
void *v; /* pointer to value */
ChanOp op; /* operation */
char *err; /* did the op fail? */
/*
* the next variables are used internally to alt
* they need not be initialized
*/
Channel **tag; /* pointer to rendez-vous tag */
int entryno; /* entry number */
};
unhandled troff command .de
unhandled troff command .ift
unhandled troff command .ifn
unhandled troff command ..
void threadmain(int argc, char *argv[])
int mainstacksize
int proccreate(void (*fn)(void*), void *arg, uint stacksize)
int procrfork(void (*fn)(void*), void *arg, uint stacksize,
int rforkflag)
int threadcreate(void (*fn)(void*), void *arg, uint stacksize)
void threadexits(char *status)
void threadexitsall(char *status)
void yield(void)
unhandled troff command .XX
int threadid(void)
int threadgetgrp(void)
int threadsetgrp(int group)
int threadpid(int id)
unhandled troff command .XX
void threadint(int id)
void threadintgrp(int group)
void threadkill(int id)
void threadkillgrp(int group)
unhandled troff command .XX
void threadsetname(char *fmt, ...)
char* threadgetname(void)
unhandled troff command .XX
void** threaddata(void)
void** procdata(void)
unhandled troff command .XX
Channel* chancreate(int elsize, int nel)
void chanfree(Channel *c)
unhandled troff command .XX
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 chanclose(Channel *c);
int chanclosing(Channel *c);
unhandled troff command .XX
void procexecl(Channel *cpid, char *file, ...)
void procexec(Channel *cpid, char *file, char *args[])
Channel* threadwaitchan(void)
unhandled troff command .XX
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).
Creation
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.
Procrfork
creates a new proc, and inside that proc creates
a single thread as
threadcreate
would,
returning the id of the created thread.
Procrfork
creates the new proc by calling
rfork
(see
fork(2))
with flags
RFPROC|RFMEM|RFNOWAIT|rforkflag.
(The thread library depends on all its procs
running in the same rendezvous group.
Do not include
RFREND
in
rforkflag.)
Proccreate
is identical to
procrfork
with
rforkflag
set to zero.
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.
Scheduling
The threads in a proc are coroutines, scheduled non-preemptively
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,
procexec,
procexecl,
threadexits,
alt,
send,
and
recv
(and the calls related to
send
and
recvsee
their descriptions further on),
plus these from
lock(2):
qlock,
rlock,
wlock,
rsleep.
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(2))
or channel communication.
System calls such as
read(2)
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.
Threadgetgrp
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.
Names and per-thread data
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.
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.
Executing new programs
Procexecl
and
procexec
are threaded analogues of
exec
and
execl
(see
exec(2));
on success,
they replace the calling thread (which must be the only thread in its proc)
and invoke the external program, never returning.
On error, they return and set
errstr.
If
cpid
is not null, the pid of the invoked program
will be sent along
cpid
once the program has been started, or –1 will be sent if an
error occurs.
Procexec
and
procexecl
will not access their arguments after sending a result
along
cpid.
Thus, programs that malloc the
argv
passed to
procexec
can safely free it once they have
received the
cpid
response.
Threadwaitchan
returns a channel of pointers to
Waitmsg
structures (see
wait(2)).
When an exec’ed process exits, a pointer to a
Waitmsg
is sent to this channel.
These
Waitmsg
structures have been allocated with
malloc(2)
and should be freed after use.
Channels
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 .
Chancreate
allocates a new channel for messages of size
elsize
and with a buffer holding
nel
messages.
If
nel
is zero, the channel is unbuffered.
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).
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,
CHANRCV
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 it 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(2)
and sends the result to the channel
c.
The string delivered by
chanprint
is allocated with
malloc(2)
and should be freed upon receipt.
Chanclose
prevents further elements being sent to the channel
c.
After closing a channel,
send
and
recv
never block.
Send
always
returns –1.
Recv
returns –1 if the channel is empty.
Alt
may choose a
CHANSND
or
CHANRCV
that failed because the channel was closed.
In this case, the
err
field of the
Alt
entry points to an error string stating that the
channel was closed and the operation was completed
with failure.
If all entries have been selected and failed because
they were closed,
alt
returns –1.
Errors, notes and resources
Thread library functions do not return on failure;
if errors occur, the entire program is aborted.
Chanclosing
returns –1 if no one called
chanclose
on the channel, and otherwise
the number of elements still in the channel.
Threaded programs should use
threadnotify
in place of
atnotify
(see
notify(2)).
It is safe to use
sysfatal
(see
perror(2))
in threaded programs.
Sysfatal
will print the error string and call
threadexitsall.
It is safe to use
rfork
(see
fork(2))
to manage the namespace, file descriptors, note group, and environment of a
single process.
That is, it is safe to call
rfork
with the flags
RFNAMEG,
RFFDG,
RFCFDG,
RFNOTEG,
RFENVG,
and
RFCENVG.
(To create new processes, use
proccreate
and
procrfork.)
As mentioned above,
the thread library depends on all procs being in the
same rendezvous group; do not change the rendezvous
group with
rfork.
FILES
/sys/lib/acid/thread
useful
acid(1)
functions for debugging threaded programs.
/sys/src/libthread/example.c
a full example program.
SOURCE
/sys/src/libthread
SEE
intro(2),
ioproc(2),
lock(2)