Parallel Programming with Pthreads

As of today, parallel programming paradigm has been backed for a while in processor level so all of us should change programming model to utilize this advanced architecture efficiently. The easiest way to consume all processor is to use multi-threaded model. In particular, you need to know basic concept of thread in general and POSIX Threads aka Pthreads for specific implementation.

What is a thread?

Technically, a thread is defined as an independent stream of instructions that can be scheduled to run as such by the operating system.

from: POSIX Threads Programming

Recent OSs allow us to run several thread simultaneously. This feature is so-called a multi-threaded model. In fact, a thread is a kind of light-weight process. Usually, a process consists of program instructions, registers, stack, heap, file descriptors and etc. A thread only consists of stack and registers. That means a thread must have its master process which has other essential pieces to share with. As a plus, creating new thread is much faster than that of process.

In short, developing multi-threaded program is not as easy as in normal model but it is not as difficult as you think. You have to concern several issues, e.g., synchronization. Imagine that you have 3 threads trying to read and write the same variable (aka counter), it is necessary to make sure that read and write operation are atomic. If all threads read at the same time and write the increment back, the counter will have the wrong value. For example, counter is 0, all threads read as 0 and write 1 back. The counter was updated 3 times so it should be 3.

Programming is like a war that programmer is a soldier. We are soldiers! We need weapons. Thread is a package of weapon. In the package, you should see many implementation of that weapon. For example, there are many kind of gun. This also applied to thread. Pthreads is actually just a standard. Linux has its own Pthreads-based implementation. GNU also has one. Fortunately, most implementation follows the Pthreads standard so you are able to write a code that may be compiled against many implementation with a few modification as long as you use standard functions.

Below are basic functions you should know.

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

int pthread_join(pthread_t thread, void **value_ptr);
int pthread_detach(pthread_t thread);

pthread_t pthread_self(void);
int pthread_equal(pthread_t t1, pthread_t t2);

int pthread_mutex_init(pthread_mutex_t *mutex,
          const pthread_mutexattr_t *attr);
int pthread_mutex_destroy(pthread_mutex_t *mutex);
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);

int pthread_cond_init(pthread_cond_t *cond,
          const pthread_condattr_t *attr);
int pthread_cond_destroy(pthread_cond_t *cond);
int pthread_cond_timedwait(pthread_cond_t *cond,
          pthread_mutex_t *mutex,
          const struct timespec *abstime);
int pthread_cond_wait(pthread_cond_t *cond,
          pthread_mutex_t *mutex);

In addition, below are advanced functions which may not be available in all implementation.

int pthread_barrier_destroy(pthread_barrier_t *barrier);
int pthread_barrier_init(pthread_barrier_t *barrier,
          const pthread_barrierattr_t *attr, unsigned count);

int pthread_barrier_wait(pthread_barrier_t *barrier);

The later ones are very useful for who are working on pipeline model where barrier is often used.

Tags: , ,

Post new comment