Semaphores provide a solution for mutual exclusion among concurrent processes by using integer variables and operations like wait() and signal(). There are two main types: counting semaphores, which have an unrestricted value domain and are used to coordinate shared resources; and binary semaphores, which are restricted to values of 0 and 1. Semaphores use queues to block processes when resources are unavailable and wakeup processes when resources become available.