Okay, let's start working on the more interesting stuff. Well, kind of. The semaphore is the only one of the thread synchronization objects that's supported on both Windows and POSIX (at least that we'll be using). That means that this class will be fairly uninteresting, as it just wraps OS functionality.
So, what is a semaphore? Well, it's kind of hard to describe, which is partly why I took so long to get around to writing this (although I'd be lying if I said laziness didn't play a part). Conceptually, you can think of a semaphore as a thread gatekeeper. Threads line up to get access to some resource, and the semaphore either lets some go (but not altering the line order - first come, first serve), or makes them wait. In effect, it's like a thread waiting queue.
Programmatically, a semaphore is a counter. This counter represents the number of threads that may yet pass through the semaphore without waiting. When it's at 0 or lower, threads will line up and wait their turn.
There are two semaphore operations: wait and post. Wait decrements the semaphore counter; if the result of the operation is negative (in other words, the counter was 0 or negative to begin with), the thread will wait its turn. Post does just the opposite: increases the counter by 1 or more, allowing that many threads to proceed. If there are fewer threads waiting than the number posted, all waiting threads will be released, and the counter will end up being nonnegative.