pnet6-threads - libpnet6's functionality regarding the use of threads. See pnet6(3) for an introduction to libpnet6.
This document describes the functions in libpnet6 that you can use to add multithreaded support to your applications.
The functions used by libpnet6 to support multithreading are heavily based on pthreads. The only reason I actually bothered to write wrappers for them is the fact that Windows of course, does not adhere to the POSIX threads standard, but then, what else is new. If you know POXIS threads, or alternatively, have worked with pthreads, you will find pnet6 threads easy to use.
Instead of writing a complete discussion on multi-threaded applications, and the use of threads and mutex locks, I advise you to read a boook on the topic, or the pthread man pages. No point in me re-writing that stuff. This man page assumes you know how to write multi-threaded applications, and only explains how you can use libpnet6 to do that.
A thread is declared in libpnet6 as a pnet_thread_id. Threads are created, and upon creation, each thread is assigned a function to execute. A thread terminates execution by returning from this function, or explicitly exit()ing. It is possible to define clean up functions that will be executed when a thread exits; more details are given later on in this document.
A thread function has the following type:
typedef void * (*PNET_THREADFUNC)( void * )
Another useful feature is to be able to send signals to other threads when certain conditions become valid. In libpnet6, we use PNET_THREAD_COND objects to implement this.
Unless otherwise stated, all functions return 0 on success, and -1 on error. On error, libpnet6 sets an error code, that can be inspected by the caller as described in pnet6-api(3).
int pnetThreadCreate( pnet_thread_id * thrd_id, PNET_THREADFUNC fun, void * fun_arg );
Creates a new thread, and assigns it the function fun to execute. The argument fun_arg is passed to the function as it is. The thread id is returned through the pointer thrd_id. Returns 0 on success (and the thread starts execution immediately); on error, -1 is returned.
void pnetThreadExit( void * pExitVal );
The calling thread exits. The variable pExitVal is made available to any other thread that performs a successful join with the calling thread.
int pnetThreadJoin( pnet_thread_id tid, void ** pValue );
The current threads is suspended wainting for the specified thread tid to terminate execution. If non-NULL, pValue is set to point to the same object that was passed to the function pnetThreadExit()
pnet_thread_id pnetThreadId( void );
Returns the ID of the calling thread.
PNET_THREAD_LOCK pnetThreadLockCreate( void );
Creates a mutex lock. Returns NULL on failure.
int pnetThreadLockClose( PNET_THREAD_LOCK lock );
Destroys the lock, and frees any memory associated with it.
int pnetThreadLockAcquire( PNET_THREAD_LOCK lock );
The calling thread acquires a locks, i.e. "locks" the lock. If the lock is locked by another thread, the calling thread blocks until the lock becomes unlocked. I suppose, nothing happens if the thread already owns the lock, i.e. the function succeeds as well.
int pnetThreadLockTryAcquire( PNET_THREAD_LOCK lock );
Same as above, except that the thread will not be blocked if the lock is currently locked; that is, the lock will be acquired if it's not locked, but the thread won't block if the lock is already locked by a different thread.
int pnetThreadLockRelease( PNET_THREAD_LOCK lock );
The calling thread releases the given lock. Any other threads that were blocked waiting for this lock are woken up and one of them (there is no way to specify which one exactly) is allowed to acquire the lock.
PNET_THREAD_COND pnetThreadCondCreate( void * attr );
Create a new condition object, with the specified attributes (currently, these are ignored, but are specified here, for future compatibility. Pass NULL for now). Upon success a new object is returned, else NULL is returned.
int pnetThreadCondFree( PNET_THREAD_COND pcond );
Free the given PNET_THREAD_COND object.
int pnetThreadCondWait( PNET_THREAD_COND pcond, PNET_THREAD_LOCK plock );
This function atomically blocks the current thread waiting on the condition variable specified by pcond, and releases the lock specified by plock. This thread will remain blocked until another thread calls pnetThreadCondSignal() of pnetThreadCondBroadcast() (see below), with the same condition pcond. Upon unblocking, the thread reacquires the lock plock.
int pnetThreadCondWaitTimed( PNET_THREAD_COND pcond, PNET_THREAD_LOCK plock ,int sec ,long nsec );
In essense, this function does exactly the same as the previous one; the difference is that the thread will only remain blocked for the given amount of time, after which it will unblock and reaquire the lock. The time to wait is specified as seconds and nanoseconds (1000ths of microseconds).
int pnetThreadCondSignal( PNET_THREAD_COND pcond );
This function wakes up one thread waiting for the given condition (see pnetThreadCondWait(), and pnetThreadCondWaitTimed()). The actual thread that is woken up is completely random (i.e. you cannot expect, or force, a specific thread to be woken up).
int pnetThreadCondBroadcast( PNET_THREAD_COND pcond );
Same as the previous function, only in this case, all threads waiting for the specified condition are woken up.
int pnetThreadSignal( int signum, int action );
Specify how the current thread is to handle the given signal. The variable signum, can be anything defined in the signal(3), or kill(1), manpages. The action variable specifies how the thread will handle the signal: allowed values are PNET_SIG_BLOCK, to block (ignore) the given signal, and PNET_SIG_UNBLOCK, to unblock (i.e. react to the given signal). Normally, unless you've specified some function to be executed with pnetSetSighandler() for the given signal, the default action for that signal is performed. See the man page on Unix signals for more exciting details.
If you pass anything else besides PNET_SIG_BLOCK or PNET_SIG_UNBLOCK as the value of action the function will fail, returning -1.
int pnetThreadKill( pnet_thread_id tid, int signum );
Send the specified signum to the given thread. Here, signum is any defined signal number as found in your system's signal(3), man page or the <signal.h>, header file.
The following few functions are highly advanced and rare (I've never used them). Read the pthread_setcancelstate man page for a fascinating discussion of cancelation states and types.
int pnetThreadSetCancelState( int state, int * oldstate);
Sets the threads cancellation-state. The two possible values are PNET_THREAD_CS_Enable, which makes the thread cancelable, and PNET_THREAD_CS_Disable, which makes the thread non-cancelable. The variable old_state is set to point to the old state of the thread, i.e. the state it had before pnetThreadSetCancelState() was called.
int pnetThreadSetCancelType( int type, int * oldtype);
Sets the thread's cancelation type. Two values are possible, PNET_THREAD_CT_Deferred and PNET_THREAD_CT_Async.
int pnetThreadTestCancel( void );
Creates a cancelation point in the calling thread. This function has no effect if cancelability is disabled.
int pnetThreadCancel( pnet_thread_id tid);
This function requests that the thread specified by tid be canceled. The target thread's cancelability state and type determines when the cancelation takes effect.
Currently, libpnet6 has no way to specify cancelation cleanup handlers, but we're working on that.
These functions are currently only a subset of the entire POSIX thread standard. I'm not planning on implementing all of the POXIS functions, only the ones that are immediately useful. Please send feature requests for the POSIX thread functions you feel need to be added.
The current version of libpnet6 is highly experimental.
You can always get the most recent version from http://pnet6.sourceforge.net.
Peter Bozarov. Send mail to kingofgib (at) users.sourceforge.net