semaphores and mutex provides synchronization services. In concurrency programming when two or more threads try to access a critical section we need a synchronization between them. This is required to avoid race conditions. Critical section and race condition are explained as
critical section is a piece of code that accesses a shared resource (data structure or device) that must not be concurrently accessed by more than one thread of execution. A critical section will usually terminate in fixed time, and a thread, task or process will have to wait a fixed time to enter it (aka bounded waiting). Some synchronization mechanism is required at the entry and exit of the critical section to ensure exclusive use, for example a semaphore.
A race condition is any situation in which the combined outcome of two or more threads of execution varies depending on the precise order in which the interleaved instructions of each are executed on the processor. For example, suppose you have two threads of execution in which one regularly increments a global variable (g_counter += 1;) and the other very occasionally zeroes it (g_counter = 0;). There is a race condition here if the increment cannot always be executed atomically (in other words, in a single instruction cycle).
Mutual exclusion lock: Block access to variables by other threads. This enforces exclusive access by a thread to a variable or set of variables. mutex is locking mechanism used to synchronize access to a resource. Only one task (can be a thread or process based on OS abstraction) can acquire the mutex. It means there will be ownership associated with mutex, and only the owner can release the lock (mutex)
Semaphore is signaling mechanism (“I am done, you can carry on” kind of signal). Think of it as an unsigned integer you can increment and decrement, but if you try to decrement it below zero, it doesn't wrap around like normal unsigned integers to, but instead it blocks the thread until another one increments it again. Semaphores usually have a maximum value; incrementing beyond this value has no effect. Decrementing the semaphore is called acquiring or locking it, incrementing is called releasing or unlocking.
Couple of article says that "binary semaphore and mutex are same" or "Semaphore with value 1 is mutex" but the basic difference is Mutex can be released only by thread that had acquired it, while you can signal semaphore from any other thread