A semaphore can count. Counting is fundamentally thread-unsafe, it is a read-modify-write operation on the processor and therefore not atomic. There are lesser primitives available to count safely, Interlocked.Increment() is atomic. But atomicity is a pretty weak threading primitive, in many cases you also have to block code when the count is at a critical value.
With 0 being "critical", all resources have been used. A standard example is counting down processor cores to run threads, once you've used them all then you should not start another thread until one of them completes and doesn't need a processor core anymore. As basic as it gets.
Binary semaphores often appear in literature about threading. A standard text-book entry and closely tied to a fellow Dutchman called Edsger Dijkstra. A pioneer in computer science that first started to think in the 1960s about what you'd do to get a processor to run multiple programs. His P and V annotation only makes sense to a Dutch speaker like me. Parkeer and Vrij are terms you use when you try to put your car somewhere :) This was long before everybody started to think about having different kinds of threading primitives, like mutex and monitor. Primitives that only require having support for a semaphore, once you got a binary semaphore then you do everything else. Building abstractions on top of a basic facility, the way composition works in software.
Noodling on a bit, I'm on a roll, one thing that makes Semaphore quite different from other primitives like Mutex and Monitor and lock is that it doesn't have thread affinity. That's a rather big deal when you write threaded code, the usual contract you try to implement is that only one thread can access a resource at the same time. All of the other .NET synchronization objects are re-entrant, you cannot deadlock yourself by taking a lock more than once on the same thread. They are very friendly and simply increment a counter when you acquire the lock. And count down again when you release. And only give up on the lock when the count reaches 0. Semaphore doesn't work that way at all, it counts when you acquire regardless of which thread acquired it. In some cases that really matters, like the count-down-the-thread-resources example I quoted earlier.
Which is really what is useful for. Not exactly very common. A monitor is the Swiss army-knife of threading, which is why it got its own keyword. The lock keyword in C#, SyncLock in VB.NET