Multithreaded Programming Guide

Similar Solaris Threads Functions

Operation 

Destination Discussion 

Create a thread 

"thr_create(3THR)"

Get the minimal stack size 

"thr_min_stack(3THR)"

Get the thread identifier 

"thr_self(3THR)"

Yield thread execution 

"thr_yield(3THR)"

Send a signal to a thread 

"thr_kill(3THR)"

Access the signal mask of the calling thread 

"thr_sigsetmask(3THR)"

Terminate a thread 

"thr_exit(3THR)"

Wait for thread termination 

"thr_join(3THR)"

Create a thread-specific data key 

"thr_keycreate(3THR)"

Set the thread-specific data key 

"thr_setspecific(3THR)"

Get the thread-specific data key 

"thr_getspecific(3THR)"

Set the thread priority 

"thr_setprio(3THR)"

Get the thread priority 

"thr_getprio(3THR)"

Create a Thread

The thr_create(3THR) routine is one of the most elaborate of all the Solaris threads library routines.

thr_create(3THR)

Usethr_create(3THR) to add a new thread of control to the current process. (For POSIX threads, see "pthread_create(3THR)".)

Note that the new thread does not inherit pending signals, but it does inherit priority and signal masks.

#include <thread.h>

int thr_create(void *stack_base, size_t stack_size,
    void *(*start_routine) (void *), void *arg, long flags,
    thread_t *new_thread);

size_t thr_min_stack(void);

stack_base--Contains the address for the stack that the new thread uses. If stack_base is NULL then thr_create() allocates a stack for the new thread with at least stack_size bytes.

stack_size--Contains the size, in number of bytes, for the stack that the new thread uses. If stack_size is zero, a default size is used. In most cases, a zero value works best. If stack_size is not zero, it must be greater than the value returned by thr_min_stack().

There is no general need to allocate stack space for threads. The threads library allocates 1 Mbyte of virtual memory for each thread's stack with no swap space reserved. (The library uses the -MAP_NORESERVE option of mmap(2) to make the allocations.)

start_routine--Contains the function with which the new thread begins execution. When start_routine() returns, the thread exits with the exit status set to the value returned by start_routine (see "thr_exit(3THR)").

arg--Can be anything that is described by void, which is typically any 4-byte value. Anything larger must be passed indirectly by having the argument point to it.

Note that you can supply only one argument. To get your procedure to take multiple arguments, encode them as one (such as by putting them in a structure).

flags--()Specifies attributes for the created thread. In most cases a zero value works best.

The value in flags is constructed from the bitwise inclusive OR of the following:


Note -

When there is no explicit synchronization to prevent it, an unsuspended, detached thread can die and have its thread ID reassigned to another new thread before its creator returns from thr_create().


new_thread--Points to a location (when new_thread is not NULL) where the ID of the new thread is stored when thr_create() is successful. The caller is responsible for supplying the storage this argument points to. The ID is valid only within the calling process.

If you are not interested in this identifier, supply a zero value to new_thread.

Return Values

Returns a zero and exits when it completes successfully. Any other returned value indicates that an error occurred. When any of the following conditions is detected, thr_create() fails and returns the corresponding value.


EAGAIN

A system limit is exceeded, such as when too many LWPs have been created.


ENOMEM

Not enough memory was available to create the new thread.


EINVAL

stack_base is not NULL and stack_size is less than the value returned by thr_min_stack.()

Stack Behavior

Stack behavior in Solaris threads is generally the same as that in pthreads. For more information about stack setup and operation, see "About Stacks".

You can get the absolute minimum on stack size by calling thr_min_stack(), which returns the amount of stack space required for a thread that executes a null procedure. Useful threads need more than this, so be very careful when reducing the stack size.

You can specify a custom stack in two ways. The first is to supply a NULL for the stack location, thereby asking the runtime library to allocate the space for the stack, but to supply the desired size in the stacksize parameter to thr_create().

The other approach is to take overall aspects of stack management and supply a pointer to the stack to thr_create(). This means that you are responsible not only for stack allocation but also for stack deallocation--when the thread terminates, you must arrange for the disposal of its stack.

When you allocate your own stack, be sure to append a red zone to its end by calling mprotect(2).

Get the Minimal Stack Size

thr_min_stack(3THR)

Use thr_min_stack(3THR) to get the minimum stack size for a thread.

#include <thread.h>

size_t thr_min_stack(void);

thr_min_stack() returns the amount of space needed to execute a null thread (a null thread is a thread that is created to execute a null procedure).

A thread that does more than execute a null procedure should allocate a stack size greater than the size of thr_min_stack().

When a thread is created with a user-supplied stack, the user must reserve enough space to run the thread. In a dynamically linked execution environment, it is difficult to know what the thread minimal stack requirements are.

Most users should not create threads with user-supplied stacks. User-supplied stacks exist only to support applications that require complete control over their execution environments.

Instead, users should let the threads library manage stack allocation. The threads library provides default stacks that should meet the requirements of any created thread.

Get the Thread Identifier

thr_self(3THR)

Use thr_self(3THR) to get the ID of the calling thread. (For POSIX threads, see "pthread_self(3THR)".)

#include <thread.h>

thread_t thr_self(void);

Yield Thread Execution

thr_yield(3THR)

thr_yield(3THR) causes the current thread to yield its execution in favor of another thread with the same or greater priority; otherwise it has no effect. There is no guarantee that a thread calling thr_yield() will do so.

#include <thread.h>

void thr_yield(void);

Send a Signal to a Thread

thr_kill(3THR)

thr_kill(3THR) sends a signal to a thread. (For POSIX threads, see "pthread_kill(3THR)".)

#include <thread.h>
#include <signal.h>
int thr_kill(thread_t target_thread, int sig);

Access the Signal Mask of the Calling Thread

thr_sigsetmask(3THR)

Use thr_sigsetmask(3THR) to change or examine the signal mask of the calling thread.

#include <thread.h>
#include <signal.h>
int thr_sigsetmask(int how, const sigset_t *set, sigset_t *oset);

Terminate a Thread

thr_exit(3THR)

Use thr_exit(3THR) to terminate a thread. (For POSIX threads, see "pthread_exit(3THR)".)

#include <thread.h>

void thr_exit(void *status);

Wait for Thread Termination

thr_join(3THR)

Use thr_join(3THR) to wait for a thread to terminate. (For POSIX threads, see "pthread_join(3THR)".)

#include <thread.h>

int thr_join(thread_t tid, thread_t *departedid, void **status);

Join specific

#include <thread.h>

thread_t tid;
thread_t departedid;
int ret;
int status;

/* waiting to join thread "tid" with status */
ret = thr_join(tid, &departedid, (void**)&status);

/* waiting to join thread "tid" without status */
ret = thr_join(tid, &departedid, NULL);

/* waiting to join thread "tid" without return id and status */
ret = thr_join(tid, NULL, NULL); 

When the tid is (thread_t)0, then thread_join() waits for any undetached thread in the process to terminate. In other words, when no thread identifier is specified, any undetached thread that exits causes thread_join() to return.

Join any

#include <thread.h>

thread_t tid;
thread_t departedid;
int ret;
int status;

/* waiting to join thread "tid" with status */
ret = thr_join(NULL, &departedid, (void **)&status); 

By indicating NULL as thread id in the Solaris thr_join(), a join will take place when any non detached thread in the process exits. The departedid will indicate the thread ID of exiting thread.

Create a Thread-Specific Data Key

Except for the function names and arguments, thread specific data is the same for Solaris as it is for POSIX. The synopses for the Solaris functions are given in this section.

thr_keycreate(3THR)

thr_keycreate(3THR) allocates a key that is used to identify thread-specific data in a process. (For POSIX threads, see "pthread_key_create(3THR)".)

#include <thread.h>

int thr_keycreate(thread_key_t *keyp,
    void (*destructor) (void *value));

Set the Thread-Specific Data Key

thr_setspecific(3THR)

thr_setspecific(3THR) binds value to the thread-specific data key, key, for the calling thread. (For POSIX threads, see "pthread_setspecific(3THR)".)

#include <thread.h>

int thr_setspecific(thread_key_t key, void *value);

Get the Thread-Specific Data Key

thr_getspecific(3THR)

thr_getspecific(3THR) stores the current value bound to key for the calling thread into the location pointed to by valuep. (For POSIX threads, see "pthread_getspecific(3THR)".)

#include <thread.h>

int thr_getspecific(thread_key_t key, void **valuep);

Set the Thread Priority

In Solaris threads, if a thread is to be created with a priority other than that of its parent's, it is created in SUSPEND mode. While suspended, the threads priority is modified using the thr_setprio(3T) function call; then it is continued.

An unbound thread is usually scheduled only with respect to other threads in the process using simple priority levels with no adjustments and no kernel involvement. Its system priority is usually uniform and is inherited from the creating process.

thr_setprio(3THR)

thr_setprio(3THR) changes the priority of the thread, specified by tid, within the current process to the priority specified by newprio. (For POSIX threads, see "pthread_setschedparam(3THR)".)

#include <thread.h>

int thr_setprio(thread_t tid, int newprio)

By default, threads are scheduled based on fixed priorities that range from zero, the least significant, to the largest integer. The tid will preempt lower-priority threads, and will yield to higher-priority threads.

thread_t tid;
int ret;
int newprio = 20;

/* suspended thread creation */
ret = thr_create(NULL, NULL, func, arg, THR_SUSPEND, &tid);

/* set the new priority of suspended child thread */
ret = thr_setprio(tid, newprio);

/* suspended child thread starts executing with new priority */
ret = thr_continue(tid);

Get the Thread Priority

thr_getprio(3THR)

Use thr_getprio(3THR) to get the current priority for the thread. Each thread inherits a priority from its creator. thr_getprio() stores the current priority, tid, in the location pointed to by newprio. (For POSIX threads, see "pthread_getschedparam(3THR)".)

#include <thread.h>

int thr_getprio(thread_t tid, int *newprio)