天天看点

Pthread API list

POSIX pthreads

Note: It is assumed that you have a good understanding of the C programming language. If you do not or need to brush up, please review basic C (including pointers and dynamic memory allocation). Here are some resources.

Now that we have a good foundation of thread concepts, lets talk about a particular thread library, POSIX pthreads. The pthread library can be found on almost any modern OS.

A few preliminary steps you should take before beginning any pthread coding is to:

  1. add

    #include <pthread.h>

    in your .c or .h header file(s)
  2. define the

    #define _REENTRANT

    macro somewhere in a common .h or .c file
  3. In your

    Makefile

    make sure gcc links against

    -lpthread

  4. Optional: add

    -D_POSIX_PTHREAD_SEMANTICS

    to your

    Makefile

    (gcc flag) for certain function calls like

    sigwait()

Pthread Basics

Now let's begin our journey into pthreads...

A thread is represented by the type

pthread_t

. Let's begin by examining most of the pthread creation and initializing functions:

int pthread_create(pthread_t *thread, pthread_attr_t *attr, 
                   void *(*start_routine)(void *), void *arg);

int pthread_attr_init(pthread_attr_t *attr);

int pthread_mutex_init(pthread_mutex_t *mutex, 
                       const pthread_mutexattr_t *mutexattr);

int pthread_cond_init(pthread_cond_t *cond, 
                      pthread_condattr_t *cond_attr);
      

pthread_create()

example:

pthread_create(&pt_worker, &thread_attributes, 
               thread_function, (void *)thread_args);
      

The above will create a pthread

pt_worker

with thread attributes defined in

thread_attributes

(this argument can be

NULL

if you want default thread attributes). The thread code is contained in the function

thread_function

and is passed in a arguments stored in

thread_args

. The

thread_function

prototype would look like this:

void *thread_function(void *args);
      

Immediately after the pthread_create call completes, the

thread_function

will begin executing.

pthread_XXXX_init()

functions initialize thread attributes, mutexes, and condition variables.

mutexattr

and

cond_attr

can be NULL if you are using defaults. Mutexes and condition variables can be initialized to default values using the

INITIALIZER

macros as well. For example:

pthread_mutex_t count_lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t count_cond = PTHREAD_COND_INITIALIZER;
      

Pthread Mutexes

To perform locks and unlocks the following functions are available for you:

int pthread_mutex_lock(pthread_mutex_t *mutex);

int pthread_mutex_trylock(pthread_mutex_t *mutex);

int pthread_mutex_unlock(pthread_mutex_t *mutex);
      

pthread_mutex_lock()

is a blocking call. If the thread cannot gain the lock, then the thread will block the thread from proceeding until it obtains the lock.

pthread_mutex_trylock()

will return immediately if the mutex cannot be locked. To unlock a mutex, simply call

pthread_mutex_unlock()

. An example on using Pthread mutexes:

pthread_mutex_lock(&count_lock);
  count++;
pthread_mutex_unlock(&count_lock);
      

In the above example, we are incrementing the globally shared

count

variable. The code between the lock and unlock calls is the critical section. Always try to minimize this section!

Pthread Condition Variables

Here are the pthread condition variable function prototypes:

int pthread_cond_wait(pthread_cond_t *cond,
                      pthread_mutex_t *mutex);

int pthread_cond_signal(pthread_cond_t *cond);

int pthread_cond_broadcast(pthread_cond_t *cond);
      

pthread_cond_wait()

puts the current thread to sleep. It requires a mutex of the associated shared resource value it is waiting on.

pthread_cond_signal()

signals one thread out of the possibly many sleeping threads to wakeup.

pthread_cond_broadcast()

signals all threads waiting on the

cond

condition variable to wakeup. Here is an example on using pthread condition variables:

pthread_mutex_lock(&count_lock);
  while (count < MAX_COUNT) {
    pthread_cond_wait(&count_cond, &count_lock);
  }
pthread_mutex_unlock(&count_lock);
      

We are locking the

count_lock

mutex so we can read the value of count without entering a potential race condition. Notice how the we use a

while

loop instead of an

if

statement. This is because of spurious wakeups problem previously mentioned. Just because a thread has been woken does not mean it was due to a

pthread_cond_signal()

or

pthread_cond_broadcast()

call. The

pthread_cond_wait()

call takes the count mutex and condition variable. Why does

pthread_cond_wait()

require the mutex as well as the conditon variable? It's because it needs to unlock the mutex when going to sleep or you would potentially enter into a deadlock!

pthread_cond_wait()

if awoken, automatically tries to reacquire the mutex, and will block if it cannot. Using the signal and broadcast functions is self-explanatory. It is recommended that you release any locks that other threads could be waiting on before you signal or broadcast.

Miscellaneous

Here are some suggestions and issues you should consider when creating using pthreads:

  • One thing we have been disregarding in the above discussions is return values. You must check all return values! No exceptions!
  • Sometimes it is desirable for a thread not to terminate (as in the case of the worker thread pool). This can be solved by placing the thread code in an infinite loop and using condition variables.
  • Many of the pthread types can be "free'd" using the

    pthread_XXXX_destroy()

    calls.
  • pthread_join()

    can be used to wait on other threads to finish (if the JOINABLE attribute is set). This is useful in creating barriers or other synchronization windows/points.
  • To set thread attributes, use the

    pthread_attr_setXXXX()

    functions. scope, schedpolicy, and detachstate are only some of the useful attributes you can set on your threads.
  • pthread_kill()

    can be used to deliver signals to specific threads.
  • pthread_self()

    returns a handle on the calling thread.
  • pthread_once()

    can be used to ensure that an initializing function within a thread is only run once.
  • There are many, many more useful functions in the pthread library. Consult your man pages or the Nichols text (Appendix C).

继续阅读