Any real-time scenarios explaining on each would be appreciated. Is there any other way to handle synchronization apart from these in pthreads. How do mutex differ from recursive-mutexes(any real-time scenario)?
A mutex can be used to protect a shared resource (a variable, a file, a peripheral device) from modifications that could leave it in an inconsistent state.
A semaphore can be used to manage a finite pool of identical shared resources (one important case of this is an IPC queue). Threads can take a resource from the pool, put one to the pool, or wait until one becomes available. Note you may still have to use a mutex in addition to a semaphore (to protect the pool data structure itself).
A read-write lock can be used to protect a shared resource that can be either read or written to (modified). All reader threads can access it simultaneously. A writer thread needs exclusive access.
A conditional variable can be used, together with a mutex, to signal events.
Wikipedia can be used to read about most of this.
This is very plainly answered in the boost::interprocess
docs
What's A Mutex?
Mutex stands for mutual exclusion and it's the most basic form of synchronization between processes. Mutexes guarantee that only one thread can lock a given mutex. If a code section is surrounded by a mutex locking and unlocking, it's guaranteed that only a thread at a time executes that section of code. When that thread unlocks the mutex, other threads can enter to that code region:
//The mutex has been previously constructed
lock_the_mutex();
//This code will be executed only by one thread //at a time.
unlock_the_mutex(); A mutex can also be recursive or non-recursive:
Recursive mutexes can be locked several times by the same thread. To fully unlock the mutex, the thread has to unlock the mutex the same times it has locked it. Non-recursive mutexes can't be locked several times by the same thread. If a mutex is locked twice by a thread, the result is undefined, it might throw an error or the thread could be blocked forever. boost interprocess docs
and
What's A Semaphore?
A semaphore is a synchronization mechanism between processes based in an internal count that offers two basic operations:
Wait: Tests the value of the semaphore count, and waits if the value is less than or equal than 0. Otherwise, decrements the semaphore count. Post: Increments the semaphore count. If any process is blocked, one of those processes is awoken. If the initial semaphore count is initialized to 1, a Wait operation is equivalent to a mutex locking and Post is equivalent to a mutex unlocking. This type of semaphore is known as a binary semaphore.
Although semaphores can be used like mutexes, they have a unique feature: unlike mutexes, a Post operation need not be executed by the same thread/process that executed the Wait operation. boost::interprocess docs
boost interprocess doesn't explicitly have things called reader-writer locks, however it does implement them using shared_locks
, and a upgrade_lock
and upgrade_to_unique lock
What's a Sharable and an Upgradable Mutex?
Sharable and upgradable mutex are special mutex types that offers more locking possibilities than a normal mutex. Sometimes, we can distinguish between reading the data and modifying the data. If just some threads need to modify the data, and a plain mutex is used to protect the data from concurrent access, concurrency is pretty limited: two threads that only read the data will be serialized instead of being executed concurrently.
If we allow concurrent access to threads that just read the data but we avoid concurrent access between threads that read and modify or between threads that modify, we can increase performance. This is specially true in applications where data reading is more common than data modification and the synchronized data reading code needs some time to execute. With a sharable mutex we can acquire 2 lock types:
Exclusive lock: Similar to a plain mutex. If a thread acquires an exclusive lock, no other thread can acquire any lock (exclusive or other) until the exclusive lock is released. If any thread other has any lock other than exclusive, a thread trying to acquire an exclusive lock will block. This lock will be acquired by threads that will modify the data. Sharable lock: If a thread acquires a sharable lock, other threads can't acquire the exclusive lock. If any thread has acquired the exclusive lock a thread trying to acquire a sharable lock will block. This locking is executed by threads that just need to read the data. With an upgradable mutex we can acquire previous locks plus a new upgradable lock:
Upgradable lock: Acquiring an upgradable lock is similar to acquiring a privileged sharable lock. If a thread acquires an upgradable lock, other threads can acquire a sharable lock. If any thread has acquired the exclusive or upgradable lock a thread trying to acquire an upgradable lock will block. A thread that has acquired an upgradable lock, is guaranteed to be able to acquire atomically an exclusive lock when other threads that have acquired a sharable lock release it. This is used for a thread that maybe needs to modify the data, but usually just needs to read the data. This thread acquires the upgradable lock and other threads can acquire the sharable lock. If the upgradable thread reads the data and it has to modify it, the thread can be promoted to acquire the exclusive lock: when all sharable threads have released the sharable lock, the upgradable lock is atomically promoted to an exclusive lock. The newly promoted thread can modify the data and it can be sure that no other thread has modified it while doing the transition. Only 1 thread can acquire the upgradable (privileged reader) lock. boost interprocess docs
C++ itself does not yet have reader-writer locks
(using shared mutexes) but @Howard Hinnet did try to get them in there, if you look here he also provides the code
C++ does not have semaphores, and mutexes are only in the new C++11 standard as far as a I know, which leads to why most of this was about boost::interprocess
© 2022 - 2024 — McMap. All rights reserved.