You are asking about a semaphore initialized to 1, which is also called a binary semaphore.
The answer depends on a particular implementation (or definition) of these primitives, however a typical difference is that monitors have thread ownership and semaphores do not. This impacts a variety of scenarios.
- For a semaphore, it is completely normal that one thread does all the ups and another one does all the downs. This should not be allowed by monitors.
- Suppose you have a class with private state and multiple public methods, all of which lock a common monitor upon entry and unlock upon exit in order to protect that state. Suppose also that public method
A
internally calls public method B
. Then a recursive monitor will correctly allow calling method A
(which involves a sequence lock-lock-unlock-unlock) whereas the same with a semaphore-implemented monitor would result in a deadlock upon the second attempt to lock, using the same thread.
- Suppose that a thread acquires a named system wide monitor and crashes. Because of thread ownership, it is possible to automatically unlock the monitor and allow any waiting threads to acquire it. With a binary semaphore this is not possible, and such a situation will typically never resolve satisfactorily until a reboot. [Edit: Note that even in case of a mutex, the described recovery mechanism may not be desirable or enabled by default, as the state of the protected resources or data structures is basically undefined after a crash midway. The decision whether to re-acquire or to recover differently is typically left to application code.]
So, a binary semaphore is similar to a monitor, but do not expect it to behave identically.