Historical Note
The first versions of UNIX had no concept of threads. Processes could be forked as shown in the example below:
pid_t child_pid = fork(); if (child_pid > 0) { printf("This is the parent process.\n"); wait(child_pid); } else { printf("This is the child process.\n"); }
Both the parent and the forked child process continue from the point fork
is called. The return value from fork is different. The two processes share the same memory on a copy-on-write basis. Later this concept was extended to threads. A thread is essentially a forked process except the memory is shared for read and write. The child process starts at the function address passed to pthread_create
Thread Creation and Destruction
pthread_create
creates a thread and returns a thread handle of typepthread_t
pthread-exit
exits a thread with a result value, althoughreturn
from the original thread function would be a better way of doing sopthread_join
waits for the child thread to complete and returns the return value from the child thread… unless the child thread is detached in which case it will return an error.
Detaching a thread
A thread can detached after its creation by calling pthread_detach
or while creating the thread as shown below:
pthread_attr_t attr; pthread_t thread; pthread_attr_init (&attr); pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); pthread_create (&thread, &attr, &thread_function, NULL); pthread_attr_destroy (&attr);
—————————————-
Thread Local Storage
pthread_keycreate
creates a key, of typepthread_key_t
whose use is explained belowpthread_setspecific
associates a pointer with a (current_thread,key) pairpthread_getspecific
gets the value associated with the (current_thread,key) pair
Mutex
pthread_mutex_init
initialises a mutex variable of typepthread_mutex_t
pthread_mutex_lock
enters critical sectionpthread_mutex_unlock
exit critical sectionpthread_mutex_trylock
waits for critical section for a finite timepthread_mutex_destroy
destroys critical section
By default a mutex is non recursive. By comparison a CRITICAL_SECTION in Windows is always recursive. A mutex can be initialised to recursive like this
pthread_mutex_t Mutex; pthread_mutexattr_t Attr; pthread_mutexattr_init(&Attr); pthread_mutexattr_settype(&Attr, PTHREAD_MUTEX_RECURSIVE); pthread_mutex_init(&Mutex, &Attr)
———————————————————————–
Semaphore
sem_init
initialise a variable of typesem_t
sem_post
signals a semaphoresem_wait
waits for a semaphoresem_getvalue
gets the current value. Equivalent functionality is not available in Windows.sem_destroy
destroys semaphore, releases associated resources
Condition Variable
pthread_cond_init
initialise a variable of typepthread_cond_t
pthread_cond_wait
releases the mutex and waits for condition variable and wakes up if mutex can be acquired again.pthread_cond_signal
signals condition variable only one thread can wake uppthread_cond_broadcast
broadcasts the signal and multiple threads can wake up if they are not using the same mutexpthread_cond_destroy
destroys condition variable
Cancelling a thread
Thread cancellation is a rather esoteric feature that I have rarely come across in well written code. A thread can be in one of three cancellation states
- asynchronously cancelable
- synchronously cancelable
- uncancellable
By default a thread is synchronously cancelable. When pthread_cancel
is called a message is posted to the thread called and when this thread calls pthread_testcancel
it gets the cancel notification. If the thread is set to asynchronously cancelable by calling pthread_setcanceltype
then the calling pthread_cancel
will terminate the callee. If the cancel state was set to uncancelable then pthread_cancel
returns with an error.
Some Observations
There is a rather uncanny resemblance between C++ threading library and pThreads. C++ does not have semaphores just yet. Semaphores can be replaced by condition variables although it does require a change in thinking. C++ has added futures, promises and atomics. For a Windows programmer the absence of events will be noticed. There is of course no need for that given mutexes and condition variables.
Conclusion
It is a lot more easier way to write multi-threaded using the C++ threading library or its cousin pThreads that to code native Windows. The only feature I miss is IO completion ports.