ref: f42e53655e9a2a1b516326f6522fba88db59a81c
dir: /sys/man/2/thread/
.TH THREAD 2 .SH 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 .SH SYNOPSIS .EX .ta 4n +4n +4n +4n +4n +4n +4n #include <u.h> #include <libc.h> #include <thread.h> .sp typedef enum { CHANEND, CHANSND, CHANRCV, CHANNOP, CHANNOBLK, } ChanOp; .sp .ta \w' 'u +\w'Channel 'u 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 */ }; .fi .de XX .ift .sp 0.5 .ifn .sp .. .PP .nf .ft L .ta \w'\fLChannel* 'u +4n +4n +4n +4n 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) .XX int threadid(void) int threadgetgrp(void) int threadsetgrp(int group) int threadpid(int id) .XX void threadint(int id) void threadintgrp(int group) void threadkill(int id) void threadkillgrp(int group) .XX void threadsetname(char *fmt, ...) char* threadgetname(void) .XX void** threaddata(void) void** procdata(void) .XX Channel* chancreate(int elsize, int nel) void chanfree(Channel *c) .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); .XX void procexecl(Channel *cpid, char *file, ...) void procexec(Channel *cpid, char *file, char *args[]) Channel* threadwaitchan(void) .XX int threadnotify(int (*f)(void*, char*), int in) .EE .SH DESCRIPTION The thread library provides parallel programming support similar to that of the languages Alef and Newsqueak. .I Threads and .I procs occupy a shared address space, communicating and synchronizing through .I channels and shared variables. .PP A .I proc is a Plan 9 process that contains one or more cooperatively-scheduled .IR threads . Programs using threads must replace .I main by .IR threadmain . The thread library provides a .I main function that sets up a proc with a single thread executing .I threadmain on a stack of size .I mainstacksize (default eight kilobytes). To set .IR mainstacksize , declare a global variable initialized to the desired value .RI ( e.g. , .B int .B mainstacksize .B = .BR 1024 ). .SS Creation .I Threadcreate creates a new thread in the calling proc, returning a unique integer identifying the thread; the thread executes .I fn(arg) on a stack of size .IR stacksize . Thread stacks are allocated in shared memory, making it valid to pass pointers to stack variables between threads and procs. .I Procrfork creates a new proc, and inside that proc creates a single thread as .I threadcreate would, returning the id of the created thread. .I Procrfork creates the new proc by calling .B rfork (see .IR fork (2)) with flags .BR RFPROC|RFMEM|RFNOWAIT| \fIrforkflag\fR. (The thread library depends on all its procs running in the same rendezvous group. Do not include .B RFREND in .IR rforkflag .) .I Proccreate is identical to .I procrfork with .I 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, .I arg should not point to data on the stack of a function that could return before the new process is scheduled. .PP .I Threadexits terminates the calling thread. If the thread is the last in its proc, .I threadexits also terminates the proc, using .I status as the exit status. .I Threadexitsall terminates all procs in the program, using .I status as the exit status. .SS 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 .IR yield , .IR proccreate , .IR procexec , .IR procexecl , .IR threadexits , .IR alt , .IR send , and .I recv (and the calls related to .I send and .IR recv \(emsee their descriptions further on), plus these from .IR lock (2): .IR qlock , .IR rlock , .IR wlock , .IR 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 .B qlocks (see .IR lock (2)) or channel communication. System calls such as .IR read (2) block the entire proc; all threads in a proc block until the system call finishes. .PP 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. .I 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. .I Threadgetgrp returns the group id for the current thread; .I threadsetgrp sets it. .I Threadpid returns the pid of the Plan 9 process containing the thread identified by .IR id , or \-1 if no such thread is found. .PP .I Threadint interrupts a thread that is blocked in a channel operation or system call. .I Threadintgrp interrupts all threads with the given group id. .I 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. .I Threadkillgrp kills all threads with the given group id. Note that .I threadkill and .I threadkillgrp will not terminate a thread that never relinquishes the processor. .SS Names and per-thread data Primarily for debugging, threads can have string names associated with them. .I Threadgetname returns the current thread's name; .I threadsetname sets it. The pointer returned by .I threadgetname is only valid until the next call to .IR threadsetname . .PP .I Threaddata returns a pointer to a per-thread pointer that may be modified by threaded programs for per-thread storage. Similarly, .I procdata returns a pointer to a per-proc pointer. .SS Executing new programs .I Procexecl and .I procexec are threaded analogues of .I exec and .I execl (see .IR 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 \-1. If .I cpid is not null, the pid of the invoked program will be sent along .I cpid once the program has been started, or \-1 will be sent if an error occurs. .I Procexec and .I procexecl will not access their arguments after sending a result along .IR cpid . Thus, programs that malloc the .I argv passed to .I procexec can safely free it once they have received the .I cpid response. .PP .I Threadwaitchan returns a channel of pointers to .B Waitmsg structures (see .IR wait (2)). When an exec'ed process exits, a pointer to a .B Waitmsg is sent to this channel. These .B Waitmsg structures have been allocated with .IR malloc (2) and should be freed after use. .SS Channels A .B Channel is a buffered or unbuffered queue for fixed-size messages. Procs and threads .I send messages into the channel and .I recv messages from the channel. If the channel is unbuffered, a .I send operation blocks until the corresponding .I recv operation occurs and .IR "vice versa" . .I Chancreate allocates a new channel for messages of size .I elsize and with a buffer holding .I nel messages. If .I nel is zero, the channel is unbuffered. .I Chanfree frees a channel that is no longer used. .I 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 .I chanfree returns immediately). .PP .I Send sends the element pointed at by .I v to the channel .IR c . If .I v is null, zeros are sent. .I Recv receives an element from .I c and stores it in .IR v . If .I v is null, the received value is discarded. .I Send and .I recv return 1 on success, \-1 if interrupted. .I Nbsend and .I nbrecv behave similarly, but return 0 rather than blocking. .PP .IR Sendp , .IR nbsendp , .IR sendul , and .I nbsendul send a pointer or an unsigned long; the channel must have been initialized with the appropriate .IR elsize . .IR Recvp , .IR nbrecvp , .IR recvul , and .I nbrecvul receive a pointer or an unsigned long; they return zero when a zero is received, when interrupted, or (for .I nbrecvp and .IR nbrecvul ) when the operation would have blocked. To distinguish between these three cases, use .I recv or .IR nbrecv . .PP .I Alt can be used to recv from or send to one of a number of channels, as directed by an array of .B Alt structures, each of which describes a potential send or receive operation. In an .B Alt structure, .B c is the channel; .B v the value pointer (which may be null); and .B op the operation: .B CHANSND for a send operation, .B CHANRCV for a recv operation; .B CHANNOP for no operation (useful when .I alt is called with a varying set of operations). The array of .B Alt structures is terminated by an entry with .I op .B CHANEND or .BR CHANNOBLK . If at least one .B Alt structure can proceed, one of them is chosen at random to be executed. .I Alt returns the index of the chosen structure. If no operations can proceed and the list is terminated with .BR CHANNOBLK , .I alt returns the index of the terminating .B CHANNOBLK structure. Otherwise, .I alt blocks until one of the operations can proceed, eventually returning the index of the structure executes. .I Alt returns \-1 when interrupted. The .B tag and .B entryno fields in the .B Alt structure are used internally by .I alt and need not be initialized. They are not used between .I alt calls. .PP .I Chanprint formats its arguments in the manner of .IR print (2) and sends the result to the channel .IR c . The string delivered by .I chanprint is allocated with .IR malloc (2) and should be freed upon receipt. .PP .I Chanclose prevents further elements being sent to the channel .IR c . After closing a channel, .I send and .I recv never block. .I Send always returns \-1. .I Recv returns \-1 if the channel is empty. .I Alt may choose a .B CHANSND or .B CHANRCV that failed because the channel was closed. In this case, the .B err field of the .B 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, .I alt returns \-1. .SS Errors, notes and resources Thread library functions do not return on failure; if errors occur, the entire program is aborted. .PP .I Chanclosing returns \-1 if no one called .I closed on the channel, and otherwise the number of elements still in the channel. .PP Threaded programs should use .I threadnotify in place of .I atnotify (see .IR notify (2)). .PP It is safe to use .B sysfatal (see .IR perror (2)) in threaded programs. .I Sysfatal will print the error string and call .IR threadexitsall . .PP It is safe to use .IR rfork (see .IR fork (2)) to manage the namespace, file descriptors, note group, and environment of a single process. That is, it is safe to call .I rfork with the flags .BR RFNAMEG , .BR RFFDG , .BR RFCFDG , .BR RFNOTEG , .BR RFENVG , and .BR RFCENVG. (To create new processes, use .I proccreate and .IR procrfork .) As mentioned above, the thread library depends on all procs being in the same rendezvous group; do not change the rendezvous group with .IR rfork . .SH FILES .TF /sys/lib/acid/thread .TP .B /sys/lib/acid/thread useful .IR acid (1) functions for debugging threaded programs. .TP .B /sys/src/libthread/example.c a full example program. .SH SOURCE .B /sys/src/libthread .SH SEE ALSO .IR intro (2), .IR ioproc (2), .IR lock (2)