I've used both POSIX threads (Pthreads) and Windows threads APIs, and I believe that Windows has the better programming model of the two. While each threading method can create threads, destroy threads, and coordinate interactions between threads, the reason I make this claim is the simplicity of use and elegance of design of the Windows threads API. This is all from the perspective of multithreaded code developers or maintainers. Let me illustrate with a few examples.
Simplicity of data types. In Pthreads, each object has its own data type (pthread_t, pthread_mutex_t, pthread_cond_t, etc.) while, in Windows threads, there is pretty much just the one type: HANDLE. For Pthreads this means different functions are used for working with each object type. Reading and understanding Pthreads code written by someone else can be straightforward. However, this does mean that the programmer must know the number, order, and type of parameters for all the different functions. On the other hand, because of the use of the same type for different objects, there is a Create* function for each different object and a corresponding Release* function for most.
Perhaps the biggest advantage of a single object data type is that there is only the one function needed to make a thread block while waiting for an object: WaitForSingleObject. Thus, only one set of parameters needs to be known regardless of whether the code is waiting on a thread, a mutex, a semaphore, or an event. The related function, WaitForMultipleObjects, is just as simple to use and easily overcomes the problem of needing to wait for multiple thread terminations one function call at a time (pthread_join) that Pthreads requires. While some may say that using a single data type for many different objects can lead to confusion when used in WaitFor* calls, programmers should set the name of the handle such that it is readily apparent whether the code is expecting a thread termination, an event to be signaled, or a mutex to be released.
WaitForMultipleObjects functionality. Besides being able to block a thread waiting for multiple thread terminations in a single call, the programmer can actually wait for any out of a set of threads to terminate. That is, even when only one thread has completed, the WaitForMultipleObjects function can be set to return and indicate which thread triggered the return. If there is specific "clean up" processing that depends on the identity of the thread that finished, this can be done before returning to wait on the remaining threads. This clean up processing will be done in the most efficient order possible, soon after each thread terminates, no matter in what order this happens. Pthreads can perform similar post-processing, but will need to wait for the threads to terminate is some fixed order. So, even if the last thread finishes first, it must wait for all the post-processing of the previous threads to be completed.
Because different objects all use the HANDLE type, a call to WaitForMultipleObjects can be set to wait for any combination of threads, mutexes, semaphores, and/or events. This feature can give the programmer a flexibility that cannot be easily (if at all) duplicated in Pthreads. As an example, I've written Windows code that used an array to hold both thread and event handles to support a threaded search through data. The ideas was to signal the blocking thread if the item being looked for was found and when the searching thread terminated; if the object was not found, the searching thread terminated without setting the event. By waiting for either handle to cause WaitForMultipleObjects to return, a simple switch statement could determine if the item had been found (and process the data) plus perform some post-processing computation upon the termination of the searching thread (regardless of whether the search was successful).
Persistence of signals. To paraphrase a classic conundrum in terms of Pthreads: If a thread signals a condition variable and no other thread is waiting, does it make a sound? The signal is lost if there is no thread waiting on the condition variable. For this reason, it is mandatory to set up a while loop to test a conditional expression (used to prompt a signal), and that requires getting a mutex involved to protect the data within the conditional expression and any changes to that data, and don't even get me started about spurious wake ups. Sheesh!
For Windows threads, once an event is in the signaled state, it stays signaled. In other words, when that tree falls, it continues to scream in pain until someone comes along to hear it. It is up to the programmer to ensure the proper switching of Windows events from the signaled to unsignaled state. Part of this involves setting the attributes of the event correctly and being sure to reset manual events as needed. All in all, this seems more convenient and simple. Besides, once the specified conditions have been achieved in order to signal the event, it's not like they can be unachieved later. Under Pthreads, if you blink, you've missed it.
These are just some of the reasons that I think Windows threads is a better threading API than Pthreads. What do you think? Do you have other reasons to prefer Windows threads? Or do you think Pthreads is the better threading method? I'd like to hear about your preferences.