POSIX Threads and Semaphores

This document describes the system calls to create and manage threads in the HP-UX version of Unix. This calls are similar to those found in Windows NT
  1. Threads
    1. Thread type
    2. Prototype function for a thread
    3. Thread Creation constants
    4. Create a thread
    5. Wait for a thread
    6. Other thread calls
  2. Semaphores
    1. Semaphore type
    2. Initializing a semaphore
    3. Semaphore operations


Threads [top ]



Thread Type [top ]

The thread header file to include is pthread.h. This header file contains the definition of a type, pthread_t. This type is basically an integer (On hawk, it is just defined as an unsigned int ). Its use is as a thread identifier.
Example: Declare two variables t1, and t2 to hold thread id's:

        #include <pthread.h>

        pthread_t t1, t2; 




Prototype function for a thread [top ]

The system call that creates a thread is passed the name of a function in the program code which that thread will execute. The prototype of this function must be like this function declaration of f. That is, one parameter of type void * and a return type, also void *. This is not a great restriction since the parameter can be the address of any item. It does generally require that the function use a conversion (or cast) on the parameter before using it.
void * f(void *p);
If f expects p to be a pointer to a double, then f might be written like this:
void * f(void *p)
{
   double *dp = (double *) p;
   double y;

   y = *dp;
   // do something with the double value in y
   ...
   
   return NULL; 
}

Thread Creation Constants [top ]

When a thread is to be created in HP-UX a flag needs to be passed to the system call to let the kernel know how to treast the thread.  The value to pass is defined as a symbolic constant in pthread.h and is of type int.
#include <pthread.h>
  pthread_att_t flags;

  flags = NULL;

Create a thread [top ]

The system call to create a thread is:
int pthread_create(
pthread_t *pthr_id, 
               long flags,
               void * (*pthr_func)(void *), 
               void * pthr_arg
               );
where,
pthr_func the function for the thread to execute
pthr_arg the argument to pass to the thread's function when it starts flags the creation flags
pthr_id the address of a thread_t variable. the function will copy the new thread id into this variable.

The return value is 0 if successful.


Wait for a thread [top ]

A thread that creates other threads can wait for any one of these threads to finish or for a particular one to finish by calling the following function.
int pthread_join(pthread_t waitfor_thr, 
             void **status);
where,
waitfor_thr thread id of a particular thread to wait for. Can be 0.
status Address of a variable. If not 0, thr_join copies the exit status of the terminated thread.

Other Thread Calls [top ]

A running thread can get its own thread id by calling pthread_self(). A thread can exit but not terminate any other thread in the process by calling pthread_exit():  A thread can yield the processor for one time by calling pthread_yield().
void pthread_exit(void *status);
thread_t pthread_self();
void sched_yield();
where status is either 0 or the address of a variable in which to store the exit status of the thread.

Semaphores [top ]


Semaphore type [top ]

The semaphore header file contains the definition of a semaphore type, sem_t. This type is a structure with several data members. However, you will not directly use any of the data members. The only way to use a semaphore is through the two functions that provide atomic operations on the semaphore. You can use the semaphore type to declare a semaphore variable, but it is not properly initialized by this declaration. A separate system call is the only way to properly initialize the semaphore.  To use Semaphores, you must link in the realtime library by specifying - lrt on the compiler or linker command line.
Example.
   #include <sys/semaphore.h>
  
    sem_t s;

Initializing a semaphore [top ]

The system call to initialize a semaphore is sem_init.
int sem_init(sem_t *sp, int type, unsigned int count);
where,
sp address of the semaphore variable to be initialized
count the initial value of the integer part of the semaphore
type a constant to indicate in processes or across process use.

The return value is 0 if successful.

Example:

  #include <sys/semaphore.h>

  sem_t s;

  if ( sem_init(&s, NULL, 1) != 0 )
  {
     // Error: initialization failed
  }

Semaphore Operations [top ]

The two operations on a properly initialized semaphore are sem_wait and sem_post:
int sem_wait(sem_t *sp);
int sem_post(sem_t *sp);

Example:

  sem_t s;

  // Assume sem_init has been called to initialize s.

  sem_wait(&s);
  ....
  sem_post(&s);